Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Format value to show 2 decimal places #52

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 37 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,57 @@
# homebridge-http-temperature-humidity
# homebridge-http-humidity

Supports https devices on HomeBridge Platform
Supports http/https devices on HomeBridge Platform.
This version only supports humidity sensors returning a JSON with the data or the raw data.

This plug-in acts as an interface between a web endpoint and homebridge only. You will still need some dedicated hardware to expose the web endpoints with the humidity information. In my case, I used an Arduino board with Wifi capabilities.

# Installation

1. Install homebridge using: npm install -g homebridge
2. Install this plugin using: npm install -g homebridge-httptemperaturehumidity
3. Update your configuration file. See sample-config.json in this repository for a sample.
1. Install homebridge using: `npm install -g homebridge`
2. Install this plugin using: `npm install -g homebridge-http-humidity`
3. Update your configuration file. See sample-config.json in this repository for a sample.

# Configuration

The available fields in the config.json file are:
- `url` [Mandatory] Endpoint URL.
- `name` [Mandatory] Accessory name.
- `http_method` [Optional] HTTP method used to get the humidity (Default: GET)
- `manufacturer` [Optional] Additional information for the accessory.
- `model` [Optional] Additional information for the accessory.
- `serial` [Optional] Additional information for the accessory.
- `field_name` [Optional] Field that will be used from the JSON response of the endpoint. Alternatively, if the `field_name` contains an empty string (`"field_name": ""`), the expected response is directly the current humidity value (Default: humidity).
- `timeout` [Optional] Waiting time for the endpoint response before fail (Default: 5000ms).
- `auth` [Optional] JSON with `user` and `pass` fields used to authenticate the request into the device.
- `update_interval` [Optional] If not zero, the field defines the polling period in milliseconds for the sensor state (Default is 120000ms). When the value is zero, the state is only updated when homebridge requests the current value.
- `debug` [Optional] Enable/disable debug logs (Default: false).


Configuration sample file:
Example:

```
"accessories": [
"accessories": [
{
"accessory": "HttpTemphum",
"name": "Living Room Weather",
"url": "http://192.168.1.210/weather",
"sendimmediately": "",
"http_method": "GET"
}
]
"accessories": [
{
"accessory": "HttpHumidity",
"name": "Outside Humidity",
"url": "http://192.168.1.210/humidity?format=json",
"http_method": "GET",
"field_name": "humidity",
"auth": {
"user": "test",
"pass": "1234"
}
}
]

```


The /weather endpoint will return a json looking like this
The defined endpoint will return a json looking like this:
```
{
"temperature": 25.8,
"humidity": 38
}
```


This plugin acts as an interface between a web endpoint and homebridge only. You will still need some dedicated hardware to expose the web endpoints with the temperature and humidity information. In my case, I used a simple NodeMCU board and a DHT11 (or DHT22).
This plugin acts as an interface between a web endpoint and homebridge only. You will still need some dedicated hardware to expose the web endpoints with the relative humidity information. In my case, I used an Arduino board with Wifi capabilities.
202 changes: 116 additions & 86 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,96 +1,126 @@
var Service, Characteristic;
var request = require('sync-request');
var request = require('request');

var temperatureService;
var humidityService;
var url
var humidity = 0;
var temperature = 0;
const DEF_TIMEOUT = 5000,
DEF_INTERVAL = 120000; //120s

module.exports = function (homebridge) {
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory("homebridge-httptemperaturehumidity", "HttpTemphum", HttpTemphum);
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
homebridge.registerAccessory("homebridge-http-humidity", "HttpHumidity", HttpHumidity);
}


function HttpTemphum(log, config) {
this.log = log;

// url info
this.url = config["url"];
this.http_method = config["http_method"] || "GET";
this.sendimmediately = config["sendimmediately"] || "";
this.name = config["name"];
this.manufacturer = config["manufacturer"] || "Luca Manufacturer";
this.model = config["model"] || "Luca Model";
this.serial = config["serial"] || "Luca Serial";
function HttpHumidity(log, config) {
this.log = log;

this.url = config["url"];
this.http_method = config["http_method"] || "GET";
this.name = config["name"];
this.manufacturer = config["manufacturer"] || "@metbosch manufacturer";
this.model = config["model"] || "Model not available";
this.serial = config["serial"] || "Non-defined serial";
this.fieldName = config["field_name"] || "humidity";
this.timeout = config["timeout"] || DEF_TIMEOUT;
this.auth = config["auth"];
this.update_interval = Number( config["update_interval"] || DEF_INTERVAL );
this.debug = config["debug"] || false;

// Internal variables
this.last_value = null;
this.waiting_response = false;
}

HttpTemphum.prototype = {

httpRequest: function (url, body, method, username, password, sendimmediately, callback) {
request({
url: url,
body: body,
method: method,
rejectUnauthorized: false
},
function (error, response, body) {
callback(error, response, body)
})
},

getStateHumidity: function(callback){
callback(null, this.humidity);
},

getState: function (callback) {
var body;

var res = request(this.http_method, this.url, {});
if(res.statusCode > 400){
this.log('HTTP power function failed');
callback(error);
} else {
this.log('HTTP power function succeeded!');
var info = JSON.parse(res.body);

temperatureService.setCharacteristic(Characteristic.CurrentTemperature, info.temperature);
humidityService.setCharacteristic(Characteristic.CurrentRelativeHumidity, info.humidity);

this.log(res.body);
this.log(info);

this.temperature = info.temperature;
this.humidity = info.humidity;

callback(null, this.temperature);
}
},

identify: function (callback) {
this.log("Identify requested!");
callback(); // success
},

getServices: function () {
var informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
.setCharacteristic(Characteristic.Model, this.model)
.setCharacteristic(Characteristic.SerialNumber, this.serial);

temperatureService = new Service.TemperatureSensor(this.name);
temperatureService
.getCharacteristic(Characteristic.CurrentTemperature)
.on('get', this.getState.bind(this));

humidityService = new Service.HumiditySensor(this.name);
humidityService
.getCharacteristic(Characteristic.CurrentRelativeHumidity)
.on('get', this.getStateHumidity.bind(this));

return [informationService, temperatureService, humidityService];
}
HttpHumidity.prototype = {

logDebug: function (str) {
if (this.debug) {
this.log(str)
}
},

updateState: function () {
//Ensure previous call finished
if (this.waiting_response) {
this.logDebug('Avoid updateState as previous response does not arrived yet');
return;
}
this.waiting_response = true;
this.last_value = new Promise((resolve, reject) => {
var ops = {
uri: this.url,
method: this.http_method,
timeout: this.timeout
};
this.logDebug('Requesting humidity on "' + ops.uri + '", method ' + ops.method);
if (this.auth) {
ops.auth = {
user: this.auth.user,
pass: this.auth.pass
};
}
request(ops, (error, res, body) => {
var value = null;
if (error) {
this.log('HTTP bad response (' + ops.uri + '): ' + error.message);
} else {
try {
value = this.fieldName === '' ? body : JSON.parse(body)[this.fieldName];
value = Number(value);
if (value < 0 || value > 100 || isNaN(value)) {
throw new Error("Invalid value received");
}
this.logDebug('HTTP successful response: ' + value);
} catch (parseErr) {
this.logDebug('Error processing received information: ' + parseErr.message);
error = parseErr;
}
}
if (!error) {
resolve(value);
} else {
reject(error);
}
this.waiting_response = false;
});
}).then((value) => {
this.humidityService
.getCharacteristic(Characteristic.CurrentRelativeHumidity).updateValue(value, null);
return value;
}, (error) => {
//For now, only to avoid the NodeJS warning about uncatched rejected promises
return error;
});
},

getState: function (callback) {
this.logDebug('Call to getState: waiting_response is "' + this.waiting_response + '"' );
this.updateState(); //This sets the promise in last_value
this.last_value.then((value) => {
callback(null, value);
return value;
}, (error) => {
callback(error, null);
return error;
});
},

getServices: function () {
this.informationService = new Service.AccessoryInformation();
this.informationService
.setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
.setCharacteristic(Characteristic.Model, this.model)
.setCharacteristic(Characteristic.SerialNumber, this.serial);

this.humidityService = new Service.HumiditySensor(this.name);
this.humidityService
.getCharacteristic(Characteristic.CurrentRelativeHumidity)
.on('get', this.getState.bind(this));

if (this.update_interval > 0) {
this.timer = setInterval(this.updateState.bind(this), this.update_interval);
}

return [this.informationService, this.humidityService];
}
};
14 changes: 8 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
{
"name": "homebridge-httptemperaturehumidity",
"version": "0.0.14",
"name": "homebridge-http-humidity",
"version": "0.3.0",
"description": "https plugin for homebridge",
"license": "ISC",
"keywords": [
"homebridge-plugin"
"homebridge-plugin",
"http",
"humidity sensor"
],
"engines": {
"node": ">=0.12.0",
"homebridge": ">=0.2.0"
},
"author": {
"name": "Luca Critelli"
"name": "@metbosch"
},
"repository": {
"type": "git",
"url": "git://github.com/lucacri/homebridge-http-temperature-humidity.git"
"url": "git://github.com/metbosch/homebridge-http-humidity.git"
},
"dependencies": {
"sync-request": "^2.1.0"
"request": "^2.5.0"
}
}
8 changes: 4 additions & 4 deletions sample-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
"port": 51826,
"pin": "031-45-156"
},

"description": "The Onion!",

"platforms": [],

"accessories": [
{
"accessory": "HttpTemphum",
"name": "Living Room Weather",
"url": "http://192.168.1.210/weather",
"accessory": "HttpHumidity",
"name": "Outside Humidity",
"url": "http://192.168.1.210/humidity?format=json",
"http_method": "GET"
}
]
Expand Down