├── .gitignore ├── .npmignore ├── .jshintrc ├── Arduino ├── connection_diagram.png ├── Arduino_Example │ └── Arduino_Example.ino └── ESP8266_Example │ └── ESP8266_Example.ino ├── .travis.yml ├── sample-config.json ├── package.json ├── LICENSE ├── README.md └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } -------------------------------------------------------------------------------- /Arduino/connection_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BardinPetr/homebridge-meteostation/HEAD/Arduino/connection_diagram.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - stable 4 | - 7 5 | - 6 6 | - 5 7 | - 4 8 | - 3 9 | - 2 10 | - 1 11 | - 0.12 12 | cache: 13 | directories: 14 | - node_modules -------------------------------------------------------------------------------- /sample-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "bridge": { 3 | "name": "Homebridge", 4 | "username": "AA:BB:CC:DD:EE:FF", 5 | "port": 51826, 6 | "pin": "123-45-678" 7 | }, 8 | 9 | "platforms": [ 10 | ], 11 | 12 | "accessories": [ 13 | { 14 | "accessory": "HomeMeteo", 15 | "name": "Meteostation", 16 | "type": "page", 17 | "url": "http://192.168.0.38", 18 | "temp_url": "/temperature", 19 | "humi_url": "/humidity", 20 | "light_url": "/light", 21 | "freq": 1000 22 | }, 23 | { 24 | "accessory": "HomeMeteo", 25 | "name": "Meteostation_JSON", 26 | "type": "json", 27 | "url": "http://192.168.0.38", 28 | "json_url": "/get", 29 | "freq": 1000 30 | } 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "homebridge-meteostation", 3 | "version": "0.7.1", 4 | "author": "BardinPetr", 5 | "license": "MIT", 6 | "description": "Plugin for Homebridge to use Arduino (ESP8266) - based home meteostation with HomeKit", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "./node_modules/jshint/bin/jshint index.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/BardinPetr/homebridge-meteostation.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/BardinPetr/homebridge-meteostation/issues" 17 | }, 18 | "homepage": "https://github.com/BardinPetr/homebridge-meteostation#readme", 19 | "keywords": [ 20 | "homebridge-plugin", 21 | "meteostation", 22 | "arduino" 23 | ], 24 | "engines": { 25 | "node": ">=0.12.0", 26 | "homebridge": ">=0.2.0" 27 | }, 28 | "dependencies": { 29 | "request": "^2.65.0" 30 | }, 31 | "devDependencies": { 32 | "jshint": "^2.9.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 BardinPetr 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Arduino/Arduino_Example/Arduino_Example.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "DHT.h" 4 | #include 5 | #include 6 | 7 | byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 8 | 9 | EthernetServer server(80); 10 | DHT dht; 11 | BH1750 lightMeter; 12 | 13 | void setup() { 14 | Serial.begin(9600); 15 | 16 | Ethernet.begin(mac); 17 | server.begin(); 18 | Serial.print("server is at "); 19 | Serial.println(Ethernet.localIP()); 20 | 21 | Wire.begin(); 22 | dht.setup(2); 23 | lightMeter.begin(); 24 | } 25 | 26 | 27 | void loop() { 28 | EthernetClient client = server.available(); 29 | if (!client) { 30 | return; 31 | } 32 | 33 | while(!client.available()){ 34 | delay(1); 35 | } 36 | 37 | String req = client.readStringUntil('\r'); 38 | client.flush(); 39 | 40 | int humidity = dht.getHumidity(); 41 | int temperature = dht.getTemperature(); 42 | int light = lightMeter.readLightLevel();; 43 | int output = 0; 44 | 45 | if (req.indexOf("/temperature") != -1) 46 | output = temperature; 47 | else if (req.indexOf("/humidity") != -1) 48 | output = humidity; 49 | else if (req.indexOf("/light") != -1) 50 | output = light; 51 | else { 52 | Serial.println("invalid request"); 53 | client.stop(); 54 | return; 55 | } 56 | 57 | client.flush(); 58 | String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\n"; 59 | s += output; 60 | s += "\n"; 61 | 62 | client.print(s); 63 | delay(1); 64 | Serial.println("Client disonnected") 65 | } 66 | 67 | -------------------------------------------------------------------------------- /Arduino/ESP8266_Example/ESP8266_Example.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include "DHT.h" 3 | 4 | const char* ssid = "your-ssid"; 5 | const char* password = "your-password"; 6 | 7 | WiFiServer server(80); 8 | DHT dht; 9 | 10 | void setup() { 11 | Serial.begin(115200); 12 | 13 | Serial.print("Connecting to "); 14 | Serial.println(ssid); 15 | 16 | WiFi.begin(ssid, password); 17 | 18 | while (WiFi.status() != WL_CONNECTED) { 19 | delay(500); 20 | Serial.print("."); 21 | } 22 | Serial.println(""); 23 | Serial.println("WiFi connected"); 24 | 25 | server.begin(); 26 | Serial.println("Server started"); 27 | 28 | Serial.println(WiFi.localIP()); 29 | 30 | dht.setup(2); 31 | } 32 | 33 | void loop() { 34 | WiFiClient client = server.available(); 35 | if (!client) { 36 | return; 37 | } 38 | 39 | while(!client.available()){ 40 | delay(1); 41 | } 42 | 43 | String req = client.readStringUntil('\r'); 44 | client.flush(); 45 | 46 | int humidity = dht.getHumidity(); 47 | int temperature = dht.getTemperature(); 48 | int output = 0; 49 | 50 | if (req.indexOf("/temperature") != -1) 51 | output = temperature; 52 | else if (req.indexOf("/humidity") != -1) 53 | output = humidity; 54 | else { 55 | Serial.println("invalid request"); 56 | client.stop(); 57 | return; 58 | } 59 | 60 | client.flush(); 61 | String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n\r\n\r\n"; 62 | s += output; 63 | s += "\n"; 64 | 65 | client.print(s); 66 | delay(1); 67 | Serial.println("Client disonnected"); 68 | } 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | homebridge-meteostation 2 | ======================= 3 | [![NPMV](https://img.shields.io/npm/v/homebridge-meteostation.svg?style=flat-square)](https://npmjs.org/package/homebridge-meteostation) [![Travis](https://img.shields.io/travis/BardinPetr/homebridge-meteostation.svg?style=flat-square)](https://travis-ci.org/BardinPetr/homebridge-meteostation) [![David](https://img.shields.io/david/BardinPetr/homebridge-meteostation.svg?style=flat-square)](https://david-dm.org/BardinPetr/homebridge-meteostation) [![NPML](https://img.shields.io/npm/l/homebridge-meteostation.svg?style=flat-square)](https://github.com/BardinPetr/homebridge-meteostation/blob/master/LICENSE) [![NPMD](https://img.shields.io/npm/dt/homebridge-meteostation.svg?style=flat-square)](https://npmjs.org/package/homebridge-meteostation) 4 | ------------------- 5 | Plugin for Homebridge to use Arduino (ESP8266) - based home meteostation with HomeKit. 6 | With this plugin You can make Your own (DIY) meteostation and connect it to smart home based on Apple HomeKit. Now You can use this characteristics: **temperature**, **humidity**, **ambient light**. 7 | 8 | Supported hardware: 9 | ------------------- 10 | 11 | You can use any **temperature**, **humidity** and **light** sensors with controller: 12 | 13 | 1. All **Arduino** boards with **WIFI/Ethernet** shield 14 | 2. **ESP8266** boards (*WeMo*, *NodeMCU* or *generic module*) 15 | 16 | Installation 17 | ============ 18 | 1. Install homebridge using: 'sudo npm install -g --unsafe-perm homebridge' 19 | 2. Install this plugin using: 'sudo npm install -g --unsafe-perm homebridge-meteostation' 20 | 3. Update your configuration file. See sample-config.json in this repository for a sample. 21 | 22 | Configuration 23 | ------------- 24 | 25 | Configuration sample: 26 | 27 | "accessories": [ 28 | { 29 | "accessory": "HomeMeteo", 30 | "name": "Meteostation", 31 | "url": "http://192.168.0.38", 32 | "temp_url": "/temperature", 33 | "humi_url": "/humidity", 34 | "light_url": "/light", 35 | "freq": 1000 36 | } 37 | ] 38 | 39 | Full example You can see in _sample-config.json_ 40 | 41 | Description of the parameters 42 | ----------------------------- 43 | 44 | |Name | Description | 45 | |---|---| 46 | |**url** | Main IP address of meteostation's controller| 47 | |**temp_url** | Page for _temperature_ value (to get temprerature will be requested **_url_** + **_temp_url_**, for example: _http://192.168.0.38/temperature_)| 48 | |**humi_url** | Page for _humidity_ value | 49 | |**light_url** | Page for _ambient light_ value (in lux), optional parameter | 50 | |**freq** | Frequency of requests to sensor in **ms**, optional parameter (standard - 1000 ms)| 51 | 52 | Controller side 53 | --------------- 54 | **Basic connection diagram** and **Code example** for Arduino Uno and ESP8266 You can find **in this repository in folder _Arduino_** -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /*jshint sub:true*/ 2 | 3 | var request = require("request"); 4 | var Service, Characteristic; 5 | 6 | module.exports = function(homebridge) { 7 | Service = homebridge.hap.Service; 8 | Characteristic = homebridge.hap.Characteristic; 9 | 10 | homebridge.registerAccessory("homebridge-meteostation", "HomeMeteo", HomeMeteoAccessory); 11 | }; 12 | 13 | function HomeMeteoAccessory(log, config) { 14 | this.log = log; 15 | this.name = config["name"]; 16 | this.url = config["url"]; 17 | this.type = config["type"] || "page"; 18 | this.json_url = config["json_url"] || null; 19 | this.temp_url = config["temp_url"]; 20 | this.humi_url = config["humi_url"]; 21 | this.light_url = config["light_url"] || null; 22 | this.freq = config["freq"] || 1000; 23 | 24 | this.temperature = 0; 25 | this.humidity = 0; 26 | this.light = 0; 27 | 28 | this.services = []; 29 | 30 | this.temperatureService = new Service.TemperatureSensor ("Temperature Sensor"); 31 | this.temperatureService 32 | .getCharacteristic(Characteristic.CurrentTemperature) 33 | .on('get', this.getValue.bind(this, 'temperature')); 34 | this.services.push(this.temperatureService); 35 | 36 | this.humidityService = new Service.HumiditySensor ("Humidity Sensor"); 37 | this.humidityService 38 | .getCharacteristic(Characteristic.CurrentRelativeHumidity) 39 | .on('get', this.getValue.bind(this, 'humidity')); 40 | this.services.push(this.humidityService); 41 | 42 | if(this.light_url !== null){ 43 | this.lightService = new Service.LightSensor ("Light Sensor"); 44 | this.lightService 45 | .getCharacteristic(Characteristic.CurrentAmbientLightLevel) 46 | .on('get', this.getValue.bind(this, 'light')); 47 | this.services.push(this.lightService); 48 | } 49 | 50 | setInterval(() => { 51 | this.getValue(null, (err, { humidity, temperature, light}) => { 52 | 53 | this.temperatureService 54 | .setCharacteristic(Characteristic.CurrentTemperature, temperature); 55 | 56 | this.humidityService 57 | .setCharacteristic(Characteristic.CurrentRelativeHumidity, humidity); 58 | 59 | if(this.light_url !== null){ 60 | this.lightService 61 | .setCharacteristic(Characteristic.CurrentAmbientLightLevel, light); 62 | } 63 | });}, this.freq); 64 | } 65 | 66 | HomeMeteoAccessory.prototype.getValue = function(name, callback) { 67 | if(type == "page"){ 68 | request(this.url + this.temp_url, (error, response, body) => { 69 | if (!error && response.statusCode == 200) { 70 | var temperature = parseInt(body, 10); 71 | if(name == "temperature"){ 72 | return callback(null, temperature); 73 | } 74 | else{ 75 | request(this.url + this.humi_url, (error, response, body) => { 76 | if (!error && response.statusCode == 200) { 77 | var humidity = parseInt(body, 10); 78 | if(name == "humidity"){ 79 | return callback(null, humidity); 80 | } 81 | else{ 82 | request(this.url + this.light_url, (error, response, body) => { 83 | if (!error && response.statusCode == 200) { 84 | var light = parseInt(body, 10); 85 | if(name == "light"){ 86 | return callback(null, light); 87 | } 88 | else{ 89 | return callback(null, { humidity: humidity, temperature: temperature, light: light }); 90 | } //End: else, name != "humidity" 91 | } //End: if OK respone 92 | }); //End: request light 93 | } //End: else, name != "humidity" 94 | } //End: if OK respone 95 | }); //End: request humidity 96 | } //End: else, name != "temperature" 97 | } //End: if OK respone 98 | }); //End: request temperature 99 | } else { 100 | request(this.url + this.json_url, (error, response, body) => { 101 | if (!error && response.statusCode == 200) { 102 | var obj = JSON.parse(body); 103 | return callback(null, { humidity: obj.humidity, temperature: obj.temperature, light: obj.light }); 104 | } 105 | }); 106 | } 107 | }; 108 | 109 | HomeMeteoAccessory.prototype.getServices = function() { 110 | return this.services; 111 | }; 112 | --------------------------------------------------------------------------------