Giter Club home page Giter Club logo

homebridge-http-webhooks's Introduction

homebridge-http-webhooks

A http plugin with support of webhooks for Homebridge.

The plugin gets its states from any system that is calling the url to trigger a state change.

Currently supports contact, motion, occupancy, smoke sensors, switches, push buttons, lights (only on/off and brightness), temperature sensors, humidity sensors, thermostats, CO2 sensors and leak sensors.

Installation

  1. Install homebridge using: npm install -g homebridge
  2. Install this plugin using: npm install -g homebridge-http-webhooks
  3. Update your configuration file. See sample-config.json snippet below.

Retrieve state

To retrieve the current state you need to call the url http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToTrigger The returned JSON format is:

    {
        "success": true,
        "state": cachedState
    }

Trigger change for boolean accessory

To trigger a change of a boolean accessory you need to call the url http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToTrigger&state=NEWSTATE

Contact sensor

For contact sensors the value for NEWSTATE is either true for contact or false for no contact. If autoRelease is used, than the state will be released after autoReleaseTime, if not set 5 seconds.

Motion sensor

For motion sensors the value for NEWSTATE is either true for motion detection or false for no motion. If autoRelease is used, than the state will be released autoReleaseTime, if not set 5 seconds.

Occupancy sensor

For occupancy sensors the value for NEWSTATE is either true for occupancy detection or 'false' for no occupancy. If autoRelease is used, than the state will be released autoReleaseTime, if not set 5 seconds.

Smoke sensor

For smoke sensors the value for NEWSTATE is either true for smoke detection or false for no smoke.

Switch

For switches the value for NEWSTATE is either true for on or false for off.

Push button

For push buttons the value for NEWSTATE is true. The button will be released automatically.

Light

For lights the value for NEWSTATE is either true for on or false for off.

Outlet

For outlets the value for NEWSTATE is either true for on or false for off.

Outlet in use

For outlets the additional state stateOutletInUse is available. The value for NEWSTATE is either true for on or false for off and can be changed by calling the url http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToTrigger&stateOutletInUse=NEWSTATE

Fanv2

For fanv2 the value for NEWSTATE is either true for on or false for off.

Valve

For valves/faucets the value for NEWSTATE is either true for on or false for off.

Valve fault state

For valves the additional state statusFault is available. The value for NEWSTATE is either true for on or false for off and can be changed by calling the url http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToTrigger&statusFault=NEWSTATE

Trigger action

Switch

For switches you can call the url from any system to switch the switch on or off.

Push button

For push buttons you can call the url from any system to push the button. The button will be released automatically.

Light

For lights you can call the url from any system to switch the light on or off.

Outlet

For outlets you can call the url from any system to switch the outlet on or off.

Fanv2

For fanv2 you can call the url from any system to switch the fanv2 on or off.

Update a numeric accessory

To update a numeric accessory you need to call the url http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&value=NEWVALUE

Temperature sensor

For temperature sensors the value for NEWVALUE is the new temperature reading.

Light sensor

For light sensors the value for NEWVALUE is the new light intensity in lux (as float).

Humidity sensor

For humidity sensors the value for NEWVALUE is the new relative humidity percentage reading.

Air Quality sensor

For air quality sensors the value for NEWVALUE is the new air quality value (Between 1-5, 1 Excellent).

CO2 Sensor

For a CO2 sensor the value for NEWVALUE is the new PPM reading.

Leak sensor

For leak sensors the value for NEWVALUE is the new leak state value (1 for leak, 0 for dry).

Light (brightness)

For light brightness the value for NEWVALUE is the new light brightness (as integer, between 0 and 100 with respect to brightness factor).

Thermostat

To update a thermostat you can update four different values:

  • Current temperature reading: http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&currenttemperature=NEWVALUE
  • Target temperature: http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targettemperature=NEWVALUE
  • Current state (Off=0 / Heating=1 / Cooling=2): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&currentstate=NEWVALUE
  • Target state (Off=0 / Heat=1 / Cool=2 / Auto=3): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targetstate=NEWVALUE

Security System

To update the state of security, you can update two different values:

  • Current state (Stay=0 / Away=1 / Night=2 / Disarmed=3 / Triggered=4): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&currentstate=NEWVALUE
  • Target state (Stay=0 / Away=1 / Night=2 / Disarm=3): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targetstate=NEWVALUE

Garage Door opener

To update a garage door opener you can update three different values:

  • Current door state (Open=0 / Closed=1 / Opening=2 / Closing=3 / Stopped=4): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&currentdoorstate=NEWVALUE
  • Target door state (Open=0 / Closed=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targetdoorstate=NEWVALUE
  • Obstruction detected (No=0 / Yes=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&obstructiondetected=NEWVALUE

Stateless switch

Stateless switches requires 3 parameters accessoryId, buttonName and the event to trigger:

  • Single press = 0
  • Double press = 1
  • Long press = 2

http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&buttonName=theButtonName&event=EVENT

Lock mechanism

To update a lock mechanism you can update two different values:

  • Current lock state (unsecured=0 / secured=1 / jammed=2 / unknown=3): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&lockcurrentstate=NEWVALUE
  • Target lock state (unsecured=0 / secured=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&locktargetstate=NEWVALUE

Window Coverings

To update a window coverings you can update three different values:

  • Current position (%): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&currentposition=%s (%s is replaced by corresponding current position)
  • Target position (%): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targetposition=%s (%s is replaced by corresponding target position) Setting of target position you can realize by send link to: open, 20%, 40%, 60% 80% and close
  • Position State (Decreasing=0 / Increasing=1 / Stopped=2): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&positionstate=0 (1 or 2) (position state is not mandatory and not fully tested yet)

If you dont use callbacks to let your covering give feedback of current position back to homekit you can set "auto_set_current_position" to true.

Fanv2

To update a fanv2 you can update five different values:

  • Rotation Speed (%): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&speed=%s (%s is replaced by fan's rotation speed)
  • Swing Mode (DISABLED=0 / ENABLED=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&swingMode=0 (or 1) (To use this feature, "enableSwingModeControls" in confing must be set to true.)
  • Rotation Direction (CLOCKWISE=0 / COUNTER_CLOCKWISE=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&rotationDirection=0 (or 1)
  • Lock Physical Controls (DISABLED=0 / ENABLED=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&lockstate=0 (or 1) (To use this feature, "enableLockPhysicalControls" in confing must be set to true.)
  • Target Fan State (MANUAL=0 / AUTO=1): http://yourHomebridgeServerIp:webhook_port/?accessoryId=theAccessoryIdToUpdate&targetState=0 (or 1)(To use this feature, "enableTargetStateControls" in confing must be set to true.)

Valves

For valves/faucets you can call the url from any system to switch the valve on or off.

Configuration

Example config.json:

    {
        "platforms": [
            {
                "platform": "HttpWebHooks",
                "webhook_port": "51828",
                "webhook_listen_host": "::", // (optional, default: "0.0.0.0")
                "webhook_enable_cors": true, // (optional, default: false)
                "cache_directory": "./.node-persist/storage", // (optional, default: "./.node-persist/storage")
                "http_auth_user": "test", // (optional, only if you like to secure your api)
                "http_auth_pass": "test", // (optional, only if you like to secure your api)
                "https": true, // (beta state, optional, only if you like to secure your api using ssl certificate)
                "https_keyfile": "/pathToKeyFile/server.key", // (beta state, optional, only if you like to secure your api using ssl certificate)
                "https_certfile": "/pathToKeyFile/server.cert", // (beta state, optional, only if you like to secure your api using ssl certificate)
                "sensors": [
                    {
                        "id": "sensor1",
                        "name": "Sensor name 1",
                        "type": "contact",
                        "autoRelease": false, // (optional)
                        "autoReleaseTime": 7500 // (optional, in ms)
                    },
                    {
                        "id": "sensor2",
                        "name": "Sensor name 2",
                        "type": "motion",
                        "autoRelease": false, // (optional)
                        "autoReleaseTime": 7500 // (optional, in ms)
                    },
                    {
                        "id": "sensor3",
                        "name": "Sensor name 3",
                        "type": "occupancy",
                        "autoRelease": false, // (optional)
                        "autoReleaseTime": 7500 // (optional, in ms)
                    },
                    {
                        "id": "sensor4",
                        "name": "Sensor name 4",
                        "type": "smoke"
                    },
                    {
                        "id": "sensor5",
                        "name": "Sensor name 5",
                        "type": "temperature"
                    },
                    {
                        "id": "sensor6",
                        "name": "Sensor name 6",
                        "type": "humidity"
                    },
                    {
                        "id": "sensor7",
                        "name": "Sensor name 7",
                        "type": "airquality"
                    },
                    {
                        "id": "sensor8",
                        "name": "Sensor name 8",
                        "type": "light"
                    },
                    {
                        "id": "sensor9",
                        "name": "Sensor name 9",
                        "type": "leak"
                    }
                ],
                "switches": [
                    {
                        "id": "switch1",
                        "name": "Switch name 1",
                        "rejectUnauthorized": false, // (optional)
                        "on_url": "your url to switch the switch on", // (optional)
                        "on_method": "GET", // (optional)
                        "on_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "on_form" for x-www-form-urlencoded JSON)
                        "on_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "off_url": "your url to switch the switch off", // (optional)
                        "off_method": "GET", // (optional)
                        "off_body": "{ \"on\": false }", // (optional only for POST, PUT and PATCH; use "off_form" for x-www-form-urlencoded JSON)
                        "off_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "pushbuttons": [
                    {
                        "id": "pushbutton1",
                        "name": "Push button name 1",
                        "rejectUnauthorized": false, // (optional)
                        "push_url": "your url to be called on push", // (optional)
                        "push_method": "GET", // (optional)
                        "push_body": "{ \"push\": true }", // (optional only for POST, PUT and PATCH; use "push_form" for x-www-form-urlencoded JSON)
                        "push_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "lights": [
                    {
                        "id": "light1",
                        "name": "Light name 1",
                        "rejectUnauthorized": false, // (optional)
                        "on_url": "your url to switch the light on", // (optional)
                        "on_method": "GET", // (optional)
                        "on_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "on_form" for x-www-form-urlencoded JSON)
                        "on_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "off_url": "your url to switch the light off", // (optional)
                        "off_method": "GET", // (optional)
                        "off_body": "{ \"on\": false }", // (optional only for POST, PUT and PATCH; use "off_form" for x-www-form-urlencoded JSON)
                        "off_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "brightness_url": "your url to change the light brightness", // (optional)
                        "brightness_method": "GET", // (optional)
                        "brightness_body": "{ \"on\" : %statusPlaceholder, \"bri\" : %brightnessPlaceholder}", // (optional only for POST, PUT and PATCH; use "brightness_form" for x-www-form-urlencoded JSON, variables are replaced on the fly)
                        "brightness_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "brightness_factor": 2.55 // (optional to convert homekit brightness to target system brightness)
                    }
                ],
                "thermostats": [
                    {
                        "id": "thermostat1",
                        "name": "Thermostat name 1",
                        "minTemp": 15, // (optional)
                        "maxTemp": 30, // (optional)
                        "minStep": 0.5, // (optional)
                        "rejectUnauthorized": false, // (optional)
                        "set_target_temperature_url": "http://127.0.0.1/thermostatscript.php?targettemperature=%f",        // %f is replaced by the target temperature
                        "set_target_temperature_method": "GET", // (optional)
                        "set_target_temperature_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "set_target_temperature_form" for x-www-form-urlencoded JSON)
                        "set_target_temperature_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "set_target_heating_cooling_state_url": "http://127.0.0.1/thermostatscript.php?targetstate=%b",     // %b is replaced by the target state
                        "set_target_heating_cooling_state_method": "GET", // (optional)
                        "set_target_heating_cooling_state_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "set_target_heating_cooling_state_form" for x-www-form-urlencoded JSON)
                        "set_target_heating_cooling_state_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "co2sensors" : [
                    {
                        "id": "co2sensor1",
                        "name": "CO2 sensor name 1",
                        "co2_peak_level": 1200
                    }
                ],
                "outlets": [
                    {
                        "id": "outlet1",
                        "name": "Outlet name 1",
                        "rejectUnauthorized": false, // (optional)
                        "on_url": "your url to switch the outlet on", // (optional)
                        "on_method": "GET", // (optional)
                        "on_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "on_form" for x-www-form-urlencoded JSON)
                        "on_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "off_url": "your url to switch the outlet off", // (optional)
                        "off_method": "GET", // (optional)
                        "off_body": "{ \"on\": false }", // (optional only for POST, PUT and PATCH; use "off_form" for x-www-form-urlencoded JSON)
                        "off_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "security": [
                    {
                        "id": "security1",
                        "name": "Security System",
                        "rejectUnauthorized": false, // (optional)
                        "set_state_url": "http://localhost/security/mode/%d", // %d is replaced by the target state
                        "set_state_method": "GET", // (optional)
                        "set_state_body": "{ \"on\": true }", // (optional only for POST, PUT and PATCH; use "set_state_form" for x-www-form-urlencoded JSON)
                        "set_state_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "garagedooropeners": [
                    {
                        "id": "garagedooropener1",
                        "name": "Garage Door Opener name 1",
                        "rejectUnauthorized": false, // (optional)
                        "open_url" : "your url to open the garage door", // (optional)
                        "open_method" : "GET", // (optional)
                        "open_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_form" for x-www-form-urlencoded JSON)
                        "open_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "close_url" : "your url to close the garage door", // (optional)
                        "close_method" : "GET", // (optional)
                        "close_body": "{ \"open\": false }", // (optional only for POST, PUT and PATCH; use "close_form" for x-www-form-urlencoded JSON)
                        "close_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "statelessswitches": [
                    {
                    "id": "statelessswitch1",
                    "name": "Stateless Switch 1",
                    "buttons": [//the buttons of the switch
                        {
                            "name": "Button1" // (The name does not appear in Home app but appear in Eve app)
                        },
                        {
                            "name": "Button2", // (The name does not appear in Home app but appear in Eve app)
                            "double_press": false, // (you can disable a type of action)
                            "long_press": false
                        }
                    ]
                    }
                ],
                "windowcoverings": [
                    {
                        "id": "windowcovering1",
                        "name": "Some Window Cover",
                        "rejectUnauthorized": false, // (optional)
                        "open_url" : "http://your.url/to/open",
                        "open_method" : "GET", // (optional)
                        "open_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_form" for x-www-form-urlencoded JSON)
                        "open_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "open_80_url" : "http://your.url/to/open80%",
                        "open_80_method" : "GET", // (optional)
                        "open_80_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_80_form" for x-www-form-urlencoded JSON)
                        "open_80_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "open_60_url" : "http://your.url/to/open60%",
                        "open_60_method" : "GET", // (optional)
                        "open_60_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_60_form" for x-www-form-urlencoded JSON)
                        "open_60_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "open_40_url" : "http://your.url/to/open40%",
                        "open_40_method" : "GET", // (optional)
                        "open_40_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_40_form" for x-www-form-urlencoded JSON)
                        "open_40_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "open_20_url" : "http://your.url/to/open20%",
                        "open_20_method" : "GET", // (optional)
                        "open_20_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_20_form" for x-www-form-urlencoded JSON)
                        "open_20_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "close_url" : "http://your.url/to/close",
                        "close_method" : "GET", // (optional)
                        "close_body": "{ \"open\": false }", // (optional only for POST, PUT and PATCH; use "close_form" for x-www-form-urlencoded JSON)
                        "close_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "auto_set_current_position": true // (optional, default: false)
                     }
                ],
                "lockmechanisms": [
                    {
                        "id": "doorlock1",
                        "name": "Door",
                        "rejectUnauthorized": false, // (optional)
                        "open_url" : "your url to open the garage door", // (optional)
                        "open_method" : "GET",// (optional)
                        "open_body": "{ \"open\": true }", // (optional only for POST, PUT and PATCH; use "open_form" for x-www-form-urlencoded JSON)
                        "open_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "close_url" : "your url to close the garage door", // (optional)
                        "close_method" : "GET", // (optional)
                        "close_body": "{ \"open\": false }", // (optional only for POST, PUT and PATCH; use "close_form" for x-www-form-urlencoded JSON)
                        "close_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ],
                "fanv2s": [
                    {
                        "id": "fanv2-1",
                        "name": "Fanv2-1",
                        "rejectUnauthorized": true, // (optional)
                        "on_url": "your url to switch the fanv2 on",
                        "on_method": "GET",
                        "on_body": "{ \"on\" : true }",
                        "on_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "off_url": "your url to switch the fanv2 off",
                        "off_method": "GET",
                        "off_body": "{ \"off\" : true }",
                        "off_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "speed_url": "your url to change the fanv2 rotation speed",
                        "speed_method": "GET",
                        "speed_body": "{ \"on\" : %statusPlaceholder, \"speed\" : %speedPlaceholder}",
                        "speed_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "speed_factor":2.55,
                        "enableLockPhysicalControls": true,
                        "lock_url": "your url to lock the fanv2's physical controls",
                        "lock_method": "GET",
                        "lock_body": "{ \"physicalLock\": true }",
                        "lock_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "unlock_url": "your url to unlock the fanv2's physical controls",
                        "unlock_method": "GET",
                        "unlock_body": "{ \"physicalLock\": false }",
                        "unlock_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "enableTargetStateControls": true,
                        "target_state_url": "your url to change the fanv2's target state",
                        "target_state_method": "GET",
                        "target_state_body": "{ \"mode\": %targetState }",
                        "target_state_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "enableSwingModeControls": true,
                        "swing_mode_url": "your url to change the fanv2's swing mode",
                        "swing_mode_method": "GET",
                        "swing_mode_body": "{ \"swing_mode\": %swingMode }",
                        "swing_mode_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}",
                        "rotation_direction_url": "your url to change the fanv2's rotation direction",
                        "rotation_direction_method": "GET",
                        "rotation_direction_body": "{ \"rotation_direction\": %rotationDirection }",
                        "rotation_direction_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}"
                    }
                ],
                "valves": [
                    {
                        "id": "valve1",
                        "name": "Valve name 1",
                        "type": "generic valve", // (optional)
                        "rejectUnauthorized": false, // (optional)
                        "on_url": "your url to switch the valve on", // (optional)
                        "on_method": "GET", // (optional)
                        "on_body": "{ \"on\" : true }", // (optional only for POST, PUT and PATCH; use "on_form" for x-www-form-urlencoded JSON)
                        "on_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}", // (optional)
                        "off_url": "your url to switch the valve off", // (optional)
                        "off_method": "GET", // (optional)
                        "off_body": "{ \"on\": false }", // (optional only for POST, PUT and PATCH; use "off_form" for x-www-form-urlencoded JSON)
                        "off_headers": "{\"Authorization\": \"Bearer ABCDEFGH\", \"Content-Type\": \"application/json\"}" // (optional)
                    }
                ]
            }
        ]
    }

Cache directory storage (cache_directory)

The cache directory is used to cache the state of the accessories. It must point to a valid and empty directory and the user that runs homebridge must have write access.

HTTPS

If you want to create a secure connection for the webhooks you need to enable it by setting https to true. Then a self signed ssl certificate will be created automatically and a secure connection will be used. If you want to use your own generated ssl certificate you can do this by setting the values for https_keyfile and https_certfile to the corresponding file paths.

homebridge-http-webhooks's People

Contributors

benzman81 avatar betorn avatar donavanbecker avatar eddyk69 avatar emptygalaxy avatar flyinglemming avatar iens avatar jcbriones avatar jsiegenthaler avatar jwktje avatar kaowiec avatar kovalev-sergey avatar mshulman avatar p-x9 avatar paolotremadio avatar ramset avatar shirnschall avatar supermamon avatar tansuka avatar teslaownertips avatar tiifuchs avatar tritter avatar wr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

homebridge-http-webhooks's Issues

airquality sensor status is 'undefined'

Hello,

I have an issue with the airquality sensor. It is not recognized by homekit:

img_1866

Here is the the config file:

{
    "platform": "HttpWebHooks",
    "webhook_port": "51828",
    "cache_directory": "./.node-persist/storage",
    "http_auth_user": "test",
    "http_auth_pass": "test",
    "sensors": [
        {
            "id": "sensor1",
            "name": "contact",
            "type": "contact"
        },
        {
            "id": "sensor2",
            "name": "airquality",
            "type": "airquality"
        }
    ]
}

Here is the homebridge log:

[2019-2-25 23:07:20] [HttpWebHooks] Getting current state for 'sensor2'...
[2019-2-25 23:07:20] [HttpWebHooks] State for 'sensor2' is 'undefined'

Could you help me to find the problem?
Regards

statelessswitches can not call urls

Hello

I will try to use the statelessswitch for Sonos (API) volume.

Example: http://192.168.1.xxx:5005/office/volume/+5

but how can set the event in the statelessswitches?

"statelessswitches": [
{
"id": "statelessswitch1",
"name": "Stateless Switch 1",
"buttons":[ //the buttons of the switch
{
"name": "Button1"
},
{
"name": "Button2",
"double_press": false, //you can disable a type of action
"long_press": false
}
]
}
],

Greeting

Securing the webhooks

Is there any way we can add user/pass auth to the webhooks?
Concerned that anyone with the correct URL could control my house!

Thanks,
Paul

Disabling callback to url, when change is detected.

I use this great plugin to send on and off events to a http based home control unit.

When the status on the control unit changes, i send a update to webhooks.

That works fine, but then it looks like webhhoks calls the on or off url, so the controller gets the same value once more.
Most of the time this works fine, but the unit is a bit slow, so sometimes this gives unwanted results.

Can you help me with how to disable this callback?.

Light Intensity example

Hello !
Can you help posting a light intensity example in config? like a window covering please? I'm having some trouble with it !

Thanks !!
very useful plugin

body as string

Hi,

I have a JSON body that I want to include in a POST request, but since the body needs to be a string, this is messing up my config. Can we allow the body as an object?

Switch activity not correctly recognised in the Home app

Pardon what may be a stupid question, but can I use this with an IFTTT maker channel to change the status of any of my existing accessories in homebridge?

I have a number of ESP8266 devices which I'd like to include in an existing IFTTT recipe to turn everything off when I leave home. At the moment I can only achieve this for the Hue and Wemo lights there are IFTTT channels for. If I could achieve this I'd be super happy!

Thanks in advance.

Paul

Support for Fans

Thanks for the webhooks plugin, can you add support for Fans.

Can't initialize accessory when using systemd

Hi, guys. Can anyone help me for my situation? When I run out systemd command "homebridge.service", below error message has been always show up and never in-service state.

4月 14 22:26:06 raspberrypi homebridge[7648]: [2019-4-14 22:26:06] [HttpWebHooks] Initializing HttpWebHooks platform...
4月 14 22:26:06 raspberrypi homebridge[7648]: /home/pi/.nvm/versions/node/v10.15.0/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/index.js:90

4月 14 22:10:21 raspberrypi systemd[1]: homebridge.service: Main process exited, code=exited, status=1/FAILURE
4月 14 22:10:21 raspberrypi systemd[1]: homebridge.service: Unit entered failed state.
4月 14 22:10:21 raspberrypi systemd[1]: homebridge.service: Failed with result 'exit-code'.

But when I execute "homebridge" command instead systemctl, it doesn't happen. Note that my homebridge is installed other several plugin like philips-hue, broadlink, etc but it hasn't seen this kind of situation.

below is my config.json
{
"platform": "HttpWebHooks",
"webhook_port": "51828",
"pushbuttons": [
{
"id": "pushbutton1",
"name": "push_button1",
"push_url": "my URL", // (optional)
"push_method": "POST" // (optional)
}
]
}

FYI, I could see HttpWebHooks can initialize my accessory when execution with homebridge command.
[2019-4-14 22:08:36] [Philipshue] Initializing Hue platform...
[2019-4-14 22:08:36] [Philipshue] homebridge-hue v0.11.12, node v10.15.0, homebridge v0.4.46
[2019-4-14 22:08:36] [HttpWebHooks] Initializing HttpWebHooks platform...
[2019-4-14 22:08:36] [HttpWebHooks] Initializing platform accessory 'push_button1'...

IFTTT not working

Hi There,

Everything i try doen't work.

When i post this URL in browser : http://rpi.oudenes.photography:51828/?accessoryId=sensor4&state=true

it works, when i put this in a IFTTT request to send URL it doesn't show in my logs at all.

Can someone tell me what i do wrong?

Even locative doesnt work as well...

Port 51828 is forwarded to the Homebridge:

Public UDP Ports: 51828
Public TCP Ports: 51828
Private IP Address: x.x.x.x
Private UDP Ports: 51828
Private TCP Ports: 51828

Issue with window covering

Hello all,

I have setup a window covering accessory as follow:
"id": "windowcovering1", "name": "Store Bureau", "open_url" : "http://myURL", "open_method" : "GET", "close_url" : "http://myURL", "close_method" : "GET"

Via the Home app, when I tap on the blind icon to set the blind up, it works: the icon shows open and the physical blind goes up.

My issue is when I tap on the blind icon to set the blind down, it does not work as expected: the physical blind goes down, but the icon shows "closing" with a spining wheel running forever.

What am I doing wrong?

thanks in advance!

History support

Is it possible to add the history support (like fakegato) so we can use Eve or other third-party controller to monitor the history of certain values, such as temperature?

Share thermostatscript.php missing file

Hello,

Thanks for this wonderful plugin. I am testing the thermostat device and noticed the thermostatscript.php missing file.
Could you this thermostatscript.php that we can find in the Example config.json?

"set_target_temperature_url": "http://127.0.0.1/thermostatscript.php?targettemperature=%f", // %f is replaced by the target temperature

Regards,

Ask for current state in Security System

Hi, is there a way to ask the current state of a security system? Currently it works for the switches, the motion sensors (by omitting the state=)...but not for the security system, it just returns "success: true".
It would be awesome if somebody added this.

Garage door closing - Set delay

is there any way I can set a delay for how long the garage opener shows opening or closing state before updating to the targetdoorstate
Currently it only displays for ~3 sec

Add as lights

Is it possible to add lights as well (Just like switches, but so they apear as lights in homekit).

Cannot make the code to work with the most recent updates

Hi I did a fresh install of everything. update nodejs, homebridge, and etc to the recent versions they have. Unfortunately, i installed this and it looks like it doesn't work as expected. I did use the npm command to install this plugin. Tried without any accessories and still causes an error. It looks like it is causing software while initializing the accessories but the plugin loaded successfully.

Error I am getting from my current config.

Jun 19 06:33:48 raspi3 systemd[1]: Started Node.js HomeKit Server.
Jun 19 06:33:50 raspi3 homebridge[6705]: [2018-6-19 06:33:50] Loaded config.json with 2 accessories and 3 platforms.
Jun 19 06:33:50 raspi3 homebridge[6705]: [2018-6-19 06:33:50] ---
Jun 19 06:33:50 raspi3 homebridge[6705]: [2018-6-19 06:33:50] Loaded plugin: homebridge-camera-ffmpeg-omx
Jun 19 06:33:50 raspi3 homebridge[6705]: [2018-6-19 06:33:50] Registering platform 'homebridge-camera-ffmpeg-omx.Camera-ffmpeg-omx'
Jun 19 06:33:50 raspi3 homebridge[6705]: [2018-6-19 06:33:50] ---
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Loaded plugin: homebridge-http-securitysystem
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-securitysystem.Http-SecuritySystem'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] ---
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Loaded plugin: homebridge-http-webhooks
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering platform 'homebridge-http-webhooks.HttpWebHooks'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookSensor'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookSwitch'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookPushButton'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookLight'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookThermostat'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-http-webhooks.HttpWebHookOutlet'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] ---
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Loaded plugin: homebridge-lockitron
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] Registering accessory 'homebridge-lockitron.Lockitron'
Jun 19 06:33:51 raspi3 homebridge[6705]: [2018-6-19 06:33:51] ---
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] Loaded plugin: homebridge-platform-insteonlocal
Jun 19 06:33:53 raspi3 homebridge[6705]: homebridge API version: 2.2
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] Registering platform 'homebridge-platform-insteonlocal.InsteonLocal'
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] ---
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] Loading 3 platforms...
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] [Camera-ffmpeg-omx] Initializing Camera-ffmpeg-omx platform...
Jun 19 06:33:53 raspi3 homebridge[6705]: [2018-6-19 06:33:53] [HttpWebHooks] Initializing HttpWebHooks platform...
Jun 19 06:33:53 raspi3 systemd[1]: homebridge.service: Main process exited, code=exited, status=1/FAILURE
Jun 19 06:33:53 raspi3 systemd[1]: homebridge.service: Unit entered failed state.
Jun 19 06:33:53 raspi3 systemd[1]: homebridge.service: Failed with result 'exit-code'.

Connection Refused

Hi,
I've successfully loaded the plug-in onto my QNAP homebridge.
However, when I tried to use Curl to trigger state change, the server responded with "Connection Refused". I cannot figure out why. Any ideas?

Garage Door

I currently have a wifi momentary relay to activate a garage door by url trigger (using webhooks pushbutton) and a wifi sensor attached to the garage door to send url status (using webhooks sensor). Would it be possible to combine the webhooks sensor function with the webhooks push button function into a webhooks garage door function (with a single open/close status and push to trigger garage door icon in homekit)? I have seen this combined function in the homebridge wemo plugin for the wemo relay.

thanks

[ERROR Http WebHook Server] No accessoryId in request.

Hi,

Most deff a noob error but for some reason I am unable to post the url to change the state of a switch. I get the error in the title.

Here is an extract of my config:

	"platform": "HttpWebHooks",
	"webhook_port": "51828",
	"cache_directory": “/var/homebridge/persist”,
	"switches": [{
		"id": "KeepAlive",
		"name": "KeepAliveSwitch"

The url I'm posting is http://publicip:51828/?KeepAlive=KeepAliveSwitch&state=true

Any ideas where i'm going wrong? I thought the accessoryid would be: KeepAlive and the accessory id to trigger would be: KeepAliveSwitch

Thanks in advance

Need some help

Need a little assistance. I have homebridge up and running great. I am trying to send the webhooks however I am little confused where to add the config.json file. I already have one under ".homebridge" location. Do I need to update that config file with some of the examples and then add my IP address? I've tried to send some local webhooks but I don't get anything to happen. How does it know what specific device I am wanting to target (shade, light or whatever it may be)?

Here is one of requests

http://192.XXX.X.X:port/?LivingShade=LivingShade&targetposition=80

I get nothing in return.

Any assistance would be great. Thanks!

Homekit "spinning wheel" on status change

Hi.
First of all, thank you for your plugin, it's great !
I've got an issue with the garage door and security system accessories.
I configured one of each of them in my HomeBridge setup, and I'm using a custom RestAPI to command my garage door and security system.
Actions are OK (when I tap the garage button in HomeKit, the garage door opens and the security system takes the right state and goes in the right state when I choose the state in HomeKit), but the HomeKit button then has the "spinning wheel" indicating the action is still running indefinitely.
Does your plugin waits for a code returned to it for validating the status has changed ? Or a callback maybe ?
Thanks.

Motion Sensor not updating in Homekit

I have created a motion sensor. Using curl, I set it status to 'true'. I can see that it changes in the homebridge. But the status does not update in the homekit app. If I exit the app and reload, status updates to show 'true'. If I then set it to 'false' it again changes in homebridge but not homekit. Again a restart of the homekit app will update the status of the sensor correctly.

Webhook callback problem

I tested 0.0.25, for the issue where a webhook change would trigger a on/off event. And at first glance i thought that your change solved the issue.

But after further investigation (Testing on 0.0.26). I can see that it don't seem to solve the problem anyway.

The way it behave right now can cause a loop between homekit and my home control system.
The reason for this is that when my home controller sends a webhook change, your program seems to update homekit, and then send the on/off url command.

Is it possible to add an option to the webhook, so it only updates homekit, but don't send the on/off url calls. I know that it propably is not what this plugin was intended for, but maybe it could be a nice feature for this plugin, so it can be used for reflecting states of another system in homekit.

Permission denied - Newbie

First of all - Thanks for the Plugin!

I wanted to setup a motion sensor

Config

{
"platform": "HttpWebHooks",
"webhook_port": "51828",
"sensors": [{
"id": "sensor2",
"name": "Eingang",
"type": "motion",
"cache_directory": "/var/homebridge/persist/",
"autoRelease": true
}]
}

Log
Getting current state for 'sensor2'...
State for 'sensor2' is 'undefined'

But if I want to send a state http://192.168.178.80:51828/?accessoryId=sensor2&state=true

Error: EACCES: permission denied, open '/.node-persist/storage/6fa6149f73dba66bcb0cfbe76fde5a94'
at Object.openSync (fs.js:443:3)
at Object.writeFileSync (fs.js:1194:35)
at LocalStorage.persistKeySync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/node-persist/src/local-storage.js:460:16)
at LocalStorage.setItemSync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/node-persist/src/local-storage.js:251:14)
at HttpWebHooksPlatform. (/usr/local/lib/node_modules/homebridge-http-webhooks/index.js:415:34)
at IncomingMessage.emit (events.js:203:15)
at endReadableNT (_stream_readable.js:1145:12)
at process._tickCallback (internal/process/next_tick.js:63:19)
Got SIGTERM, shutting down Homebridge...

Window Covering

Thanks very much for the garage door function. Would it possible to have similar functionality for garagedoor but using the windowcovering accessory type in homekit (eg for window blinds or curtains)?

lockmechanisms not working correctly: open url only

Hello, I've used the "lockmechanisms" to control a remote lock by http and receive back the status as following

"lockmechanisms": [
{
"id": "doorlock",
"name": "Main door",
"open_url" : "http://ipaddress/?Id=1&val=0",
"open_method" : "GET",
"close_url" : "http://ipaddress/?Id=1&val=1",
"close_method" : "GET"
}
]

From remote lock I update correctly the status via webhooks (it works well).
The problem is, even if the status is "locked" or "unlocked" (correctly shown by interface) the url sent by the plugin is always the "open_url" , never the "close" one. Just to be clear, if the status is "close" and I click on interface it opens the door, and the status switches on "open", If now I click again to "close" it sends "nothing".

Is it a bug or am I wrong on something?

Rob

[ERROR Http WebHook Server] No accessoryId in request.

Hello - I've started randomly getting these errors in my homebridge log. I haven't changed any configuration. Could you help me diagnose these further - how can I tell where the request is coming from and what the content (or lack of) is?

Thanks in advance,
Paul

support commands additional to urls

Hello, may I suggest to add also commands (curl, php etc) not only http requests to turn on or off elements on homekit? As the plugin homebridge-cmdSwitch2 works, it could be great to have "on_cmd" and "off_cmd" instead of "on_url" and "off_url", a mix between commands and webhooks for notifications could be awesome.
Thanks

Permission error when running on docker

[9/1/2019, 9:16:26 PM] Error: EACCES: permission denied, mkdir '/run/s6/services/homebridge/.node-persist'

This is fixed by using the proper volume path, "cache_directory": "/homebridge/.node-persist", for example.

Maybe it should be added to the documentation?

Can't update or re-install :(

Tried to update to 0.0.43, then all hell broke loose.

All I get is this;
npm ERR! path /usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/bin/cmd.js
npm ERR! code ENOENT
npm ERR! errno -2
npm ERR! syscall chmod
npm ERR! enoent ENOENT: no such file or directory, chmod '/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/bin/cmd.js'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/dk/.npm/_logs/2018-12-22T19_43_23_654Z-debug.log

Using node 6.9.1 and npm 6.5.0

Can't install any version now :(

Any suggestions?

Push button cached state not being released

Calling the web hook for a push button works the 1st time, then the “true” state is cached on the node_persist/storage directory
I have to change it to false manually in order to make it work again

EACCES error when running via launchd on macOS

When I run via terminal everything works, but get an EACCES error when running as a daemon via launchd. See log below. Any thoughts on how to run as a daemon?

[2017-8-22 22:07:31] Initializing HttpWebHooks platform...
/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/index.js:90
throw err0;
^

Error: EACCES: permission denied, mkdir '/~/.node-persist'
at Object.fs.mkdirSync (fs.js:891:18)
at sync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/index.js:71:13)
at Function.sync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/mkdirp/index.js:77:24)
at LocalStorage.parseStorageDirSync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/node-persist/src/local-storage.js:600:20)
at LocalStorage.initSync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/node-persist/src/local-storage.js:141:14)
at Object.nodePersist.initSync (/usr/local/lib/node_modules/homebridge-http-webhooks/node_modules/node-persist/src/node-persist.js:37:32)
at HttpWebHooksPlatform (/usr/local/lib/node_modules/homebridge-http-webhooks/index.js:25:18)
at Server._loadPlatforms (/usr/local/lib/node_modules/homebridge/lib/server.js:294:32)
at Server.run (/usr/local/lib/node_modules/homebridge/lib/server.js:80:36)
at module.exports (/usr/local/lib/node_modules/homebridge/lib/cli.js:40:10)
at Object. (/usr/local/lib/node_modules/homebridge/bin/homebridge:17:22)
at Module._compile (module.js:573:30)
at Object.Module._extensions..js (module.js:584:10)
at Module.load (module.js:507:32)
at tryModuleLoad (module.js:470:12)
at Function.Module._load (module.js:462:3)

Publish new version?

I was getting errors while trying to implement occupancy sensors, when I realized that the version published to the NPM repo doesn't yet have these. I installed the current master instead, and it seems to work just fine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.