diff --git a/DeviceHiveESP8266.md b/DeviceHiveESP8266.md index 8e10f47..20ab47a 100644 --- a/DeviceHiveESP8266.md +++ b/DeviceHiveESP8266.md @@ -52,6 +52,7 @@ * [devices/si7021/read](#devicessi7021read) * [devices/bmp180/read](#devicesbmp180read) * [devices/bmp280/read](#devicesbmp280read) + * [devices/bme280/read](#devicesbme280read) * [devices/bh1750/read](#devicesbh1750read) * [devices/mpu6050/read](#devicesmpu6050read) * [devices/hmc5883l/read](#deviceshmc5883lread) @@ -274,7 +275,7 @@ Sets gpio pins according to parameters specified. Pins will be automatically ini JSON with a set of key-value pairs, where key is pin number and value "0" for LOW, "1" for HIGH or "x" for NOP, leaving pin unaffected. Sample below sets `GPIO10` to LOW and `GPIO11` to HIGH: ```json -{ +{ "10":"0", "11":"1", "12":"x" @@ -294,7 +295,7 @@ JSON with a set of key-value pairs, where key is pin number and value is one of *Example*: ```json -{ +{ "10":"init", "11":"pullup", "12":"nopull" @@ -568,11 +569,11 @@ Read data from SPI bus. *Parameters*: * "count" - number of bytes that should be read. If not specified, 2 bytes will be read. Can not be 0. * "data" - base64 encoded data that should be sent before reading. Maximum size of data is 264 bytes. -* "mode" - Select SPI clock mode. Can be: - * 0 - Low clock polarity, front edge - * 1 - Low clock polarity, rear edge - * 2 - High clock polarity, front edge - * 3 - High clock polarity, rear edge +* "mode" - Select SPI clock mode. Can be: + * 0 - Low clock polarity, front edge + * 1 - Low clock polarity, rear edge + * 2 - High clock polarity, front edge + * 3 - High clock polarity, rear edge * If not specified, previous mode will be used. Default is 0. * "CS" - GPIO port number for CS(chip select) line. If not specified, previous pin will be used. Can be "x" for disabling CS usage. Default is "x". Can not be the same pin as used for other SPI data communication. @@ -925,6 +926,32 @@ Return "OK" in status and json like below in result on success. Or "Error" and d ``` Temperature unit in Celsius degrees. Pressure unit is pascal. +## devices/bme280/read +Read temperature, pressure and humidity from BME280 sensor. + +*Parameters*: +* "address" - I2C BME280 device address. Behavior is the same as i2c interface, except it can be omitted. If not specified, previous will be used. Default is 0xEC. +* "SDA" - GPIO port number for SDA data line. Behavior and default are common with i2c interface. +* "SCL" - GPIO port number for SCL data line. Behavior and default are common with i2c interface. + +*Example*: +```json +{ + "SDA":"4", + "SCL":"5", + "address":"0xEE" +} +``` +Return "OK" in status and json like below in result on success. Or "Error" and description in result on error. +```json +{ + "temperature":24.5000, + "pressure":100312.2000, + "humidity":25.1000 +} +``` +Temperature unit in Celsius degrees. Pressure unit is pascal. Humidity is %RH. + ## devices/bh1750/read Read illuminance from BH1750 sensor. Mode is 'High Resolution2'. @@ -1289,7 +1316,7 @@ Enable or disable PWM. Chip has 16 PWM channels with 12 bit resolution. *Parameters*: Json with set of key-value, where key is pin name and value is duty cycle. Duty cycle is a float value between 0..100, i.e. percent. Mnemonic pin "all" also can be used to control all GPIO pins simultaneously. To disable PWM for one of the outputs, just set value to "disable" or "0". There are also additional parameters: -* "frequency" - set PWM base frequency, if this parameter was omitted, previous frequency will be used. "frequency" also can be set while PWM working or before command with pins duty cycles. Default frequency is 200 Hz. Minimum frequency is 24 Hz, maximum is 1526 Hz. There is a presceler in the chip, so frequency is not precise. +* "frequency" - set PWM base frequency, if this parameter was omitted, previous frequency will be used. "frequency" also can be set while PWM working or before command with pins duty cycles. Default frequency is 200 Hz. Minimum frequency is 24 Hz, maximum is 1526 Hz. There is a presceler in the chip, so frequency is not precise. * "address" - I2C PCA9685 device address. Behavior is the same as i2c interface, except it can be omitted. If not specified, previous pin will be used. Default is 0x80. * "SDA" - GPIO port number for SDA data line. Behavior and default are common with i2c interface. * "SCL" - GPIO port number for SCL data line. Behavior and default are common with i2c interface. @@ -1421,5 +1448,5 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I 该软件按本来的样子提供,没有任何明确或暗含的担保,包括但不仅限于关于试销性、适合某一特定用途和非侵权的保证。作者和版权持有人在任何情况下均不就由软件或软件使用引起的以合同形式、民事侵权或其它方式提出的任何索赔、损害或其它责任负责。 - + All trademarks, service marks, trade names, trade dress, product names and logos appearing on the firmware repository are the property of their respective owners. diff --git a/firmware-src/sources/commands/bmp280_cmd.c b/firmware-src/sources/commands/bmp280_cmd.c deleted file mode 100644 index 64bc0d6..0000000 --- a/firmware-src/sources/commands/bmp280_cmd.c +++ /dev/null @@ -1,54 +0,0 @@ -/** - * @file - * @brief BMP280 command handlers. - * @copyright 2016 [DeviceHive](http://devicehive.com) - * @author Nikolay Khabarov - */ -#include "commands/bmp280_cmd.h" -#include "commands/i2c_cmd.h" -#include "devices/bmp280.h" -#include "DH/i2c.h" -#include "DH/adc.h" - -#include "dhcommand_parser.h" -#include - -#if defined(DH_COMMANDS_BMP280) && defined(DH_DEVICE_BMP280) - -/* - * dh_handle_devices_bmp280_read() implementation. - */ -void ICACHE_FLASH_ATTR dh_handle_devices_bmp280_read(COMMAND_RESULT *cmd_res, const char *command, - const char *params, unsigned int params_len) -{ - gpio_command_params info; - ALLOWED_FIELDS fields = 0; - if (params_len) { - const char *err_msg = parse_params_pins_set(params, params_len, - &info, DH_ADC_SUITABLE_PINS, 0, - AF_SDA | AF_SCL | AF_ADDRESS, &fields); - if (err_msg != 0) { - dh_command_fail(cmd_res, err_msg); - return; // FAILED - } - if (fields & AF_ADDRESS) - bmp280_set_address(info.address); - } - - fields |= AF_ADDRESS; - if (dh_i2c_init_helper(cmd_res, fields, &info)) - return; // FAILED - - float temperature; - float pressure; - const int status = bmp280_read(DH_I2C_NO_PIN, DH_I2C_NO_PIN, &pressure, &temperature); - const char *err_msg = dh_i2c_error_string(status); - if (err_msg != 0) { - dh_command_fail(cmd_res, err_msg); - } else { - cmd_res->callback(cmd_res->data, DHSTATUS_OK, RDT_FORMAT_JSON, - "{\"temperature\":%f, \"pressure\":%f}", temperature, pressure); - } -} - -#endif /* DH_COMMANDS_BMP280 && DH_DEVICE_BMP280 */ diff --git a/firmware-src/sources/commands/bmp280_cmd.h b/firmware-src/sources/commands/bmp280_cmd.h deleted file mode 100644 index 5e1bb86..0000000 --- a/firmware-src/sources/commands/bmp280_cmd.h +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @file - * @brief BMP280 command handlers. - * @copyright 2016 [DeviceHive](http://devicehive.com) - * @author Nikolay Khabarov - */ -#ifndef _COMMANDS_BMP280_CMD_H_ -#define _COMMANDS_BMP280_CMD_H_ - -#include "user_config.h" -#if defined(DH_COMMANDS_BMP280) && defined(DH_DEVICE_BMP280) -#include "dhsender_data.h" - -/** - * @brief Handle "devices/bmp280/read" command. - */ -void dh_handle_devices_bmp280_read(COMMAND_RESULT *cmd_res, const char *command, - const char *params, unsigned int params_len); - -#endif /* DH_COMMANDS_BMP280 && DH_DEVICE_BMP280 */ -#endif /* _COMMANDS_BMP280_CMD_H_ */ diff --git a/firmware-src/sources/commands/bmx280_cmd.c b/firmware-src/sources/commands/bmx280_cmd.c new file mode 100644 index 0000000..e767845 --- /dev/null +++ b/firmware-src/sources/commands/bmx280_cmd.c @@ -0,0 +1,86 @@ +/** + * @file + * @brief BMP280 and BME280 command handlers. + * @copyright 2016 [DeviceHive](http://devicehive.com) + * @author Nikolay Khabarov + */ +#include "commands/i2c_cmd.h" +#include "DH/i2c.h" +#include "DH/adc.h" + +#include "dhcommand_parser.h" +#include +#include "../devices/bmx280.h" +#include "bmx280_cmd.h" + +#if defined(DH_COMMANDS_BMX280) && defined(DH_DEVICE_BMX280) + +/* + * Sensor initialization + */ +LOCAL int ICACHE_FLASH_ATTR dh_handle_devices_bmx280_prepare(COMMAND_RESULT *cmd_res, const char *command, + const char *params, unsigned int params_len) +{ + gpio_command_params info; + ALLOWED_FIELDS fields = 0; + if (params_len) { + const char *err_msg = parse_params_pins_set(params, params_len, + &info, DH_ADC_SUITABLE_PINS, 0, + AF_SDA | AF_SCL | AF_ADDRESS, &fields); + if (err_msg != 0) { + dh_command_fail(cmd_res, err_msg); + return 0; // FAILED + } + if (fields & AF_ADDRESS) + bmx280_set_address(info.address); + } + + fields |= AF_ADDRESS; + if (dh_i2c_init_helper(cmd_res, fields, &info)) + return 0; // FAILED + return 1; +} + + +/* + * dh_handle_devices_bmp280_read() implementation. + */ +void ICACHE_FLASH_ATTR dh_handle_devices_bmp280_read(COMMAND_RESULT *cmd_res, const char *command, + const char *params, unsigned int params_len) +{ + if(!dh_handle_devices_bmx280_prepare(cmd_res, command, params, params_len)) + return; + float temperature; + float pressure; + const int status = bmx280_read(DH_I2C_NO_PIN, DH_I2C_NO_PIN, &pressure, &temperature, 0); + const char *err_msg = dh_i2c_error_string(status); + if (err_msg != 0) { + dh_command_fail(cmd_res, err_msg); + } else { + cmd_res->callback(cmd_res->data, DHSTATUS_OK, RDT_FORMAT_JSON, + "{\"temperature\":%f, \"pressure\":%f}", temperature, pressure); + } +} + +/* + * dh_handle_devices_bme280_read() implementation. + */ +void ICACHE_FLASH_ATTR dh_handle_devices_bme280_read(COMMAND_RESULT *cmd_res, const char *command, + const char *params, unsigned int params_len) +{ + if(!dh_handle_devices_bmx280_prepare(cmd_res, command, params, params_len)) + return; + float temperature; + float pressure; + float humidity; + const int status = bmx280_read(DH_I2C_NO_PIN, DH_I2C_NO_PIN, &pressure, &temperature, &humidity); + const char *err_msg = dh_i2c_error_string(status); + if (err_msg != 0) { + dh_command_fail(cmd_res, err_msg); + } else { + cmd_res->callback(cmd_res->data, DHSTATUS_OK, RDT_FORMAT_JSON, + "{\"temperature\":%f, \"pressure\":%f, \"humidity\":%f}", temperature, pressure, humidity); + } +} + +#endif /* DH_COMMANDS_BMX280 && DH_DEVICE_BMX280 */ diff --git a/firmware-src/sources/commands/bmx280_cmd.h b/firmware-src/sources/commands/bmx280_cmd.h new file mode 100644 index 0000000..b1d4df3 --- /dev/null +++ b/firmware-src/sources/commands/bmx280_cmd.h @@ -0,0 +1,27 @@ +/** + * @file + * @brief BMP280 and BME280 command handlers. + * @copyright 2016 [DeviceHive](http://devicehive.com) + * @author Nikolay Khabarov + */ +#ifndef _COMMANDS_BMX280_CMD_H_ +#define _COMMANDS_BMX280_CMD_H_ + +#include "user_config.h" +#if defined(DH_COMMANDS_BMX280) && defined(DH_DEVICE_BMX280) +#include "dhsender_data.h" + +/** + * @brief Handle "devices/bmp280/read" command. + */ +void dh_handle_devices_bmp280_read(COMMAND_RESULT *cmd_res, const char *command, + const char *params, unsigned int params_len); + +/** + * @brief Handle "devices/bme280/read" command. + */ +void dh_handle_devices_bme280_read(COMMAND_RESULT *cmd_res, const char *command, + const char *params, unsigned int params_len); + +#endif /* DH_COMMANDS_BMX280 && DH_DEVICE_BMX280 */ +#endif /* _COMMANDS_BMX280_CMD_H_ */ diff --git a/firmware-src/sources/devices/bmp280.c b/firmware-src/sources/devices/bmx280.c similarity index 57% rename from firmware-src/sources/devices/bmp280.c rename to firmware-src/sources/devices/bmx280.c index 2fbc567..b14027b 100644 --- a/firmware-src/sources/devices/bmp280.c +++ b/firmware-src/sources/devices/bmx280.c @@ -1,46 +1,46 @@ /** * @file - * @brief Simple communication with BMP280 pressure sensor. + * @brief Simple communication with BMP280 and BME280 sensors. * @copyright 2016 [DeviceHive](http://devicehive.com) * @author Nikolay Khabarov */ -#include "devices/bmp280.h" +#include "devices/bmx280.h" #include "DH/i2c.h" #include "dhdebug.h" #include "dhutils.h" #include -#if defined(DH_DEVICE_BMP280) +#if defined(DH_DEVICE_BMX280) /** @brief Default sensor i2c address*/ -#define BMP280_DEFAULT_ADDRESS 0xEC +#define BMX280_DEFAULT_ADDRESS 0xEC // module variables -static int mAddress = BMP280_DEFAULT_ADDRESS; +static int mAddress = BMX280_DEFAULT_ADDRESS; /* - * bmp280_read() implementation. + * bmx280_read() implementation. */ -int ICACHE_FLASH_ATTR bmp280_read(int sda, int scl, float *pressure, float *temperature) +int ICACHE_FLASH_ATTR bmx280_read(int sda, int scl, float *pressure, float *temperature, float *humidity) { int status; if (sda != DH_I2C_NO_PIN && scl != DH_I2C_NO_PIN) { if ((status = dh_i2c_init(sda, scl)) != DH_I2C_OK) { - dhdebug("bmp280: failed to set up pins"); + dhdebug("bmx280: failed to set up pins"); return status; } } - char buf[24]; + char buf[26]; buf[0] = 0x88; // get factory parameters if ((status = dh_i2c_write(mAddress, buf, 1, 0)) != DH_I2C_OK) { - dhdebug("bmp280: failed to write get coefficients command"); + dhdebug("bmx280: failed to write get coefficients command"); return status; } if ((status = dh_i2c_read(mAddress, buf, sizeof(buf))) != DH_I2C_OK) { - dhdebug("bmp280: failed to read coefficients"); + dhdebug("bmx280: failed to read coefficients"); return status; } double T1 = (double)unsignedInt16le(buf, 0); @@ -55,40 +55,71 @@ int ICACHE_FLASH_ATTR bmp280_read(int sda, int scl, float *pressure, float *temp double P7 = (double)signedInt16le(buf, 18); double P8 = (double)signedInt16le(buf, 20); double P9 = (double)signedInt16le(buf, 22); + double H1 = (double)((unsigned char)buf[25]); + + double H2 = 0.0; + double H3 = 0.0; + double H4 = 0.0; + double H5 = 0.0; + double H6 = 0.0; + + if (humidity) { + buf[0] = 0xE1; // get factory parameters for humidity + if ((status = dh_i2c_write(mAddress, buf, 1, 0)) != DH_I2C_OK) { + dhdebug("bmx280: failed to write get humidity coefficients command"); + return status; + } + if ((status = dh_i2c_read(mAddress, buf, 7)) != DH_I2C_OK) { + dhdebug("bmx280: failed to read humidity coefficients"); + return status; + } + H2 = (double)signedInt16le(buf, 0); + H3 = (double)((unsigned char)buf[2]); + signed short v = buf[3]; + v = v << 4; + v |= buf[4] & 0b00001111; + H4 = (double)v; + v = buf[5]; + v = v << 4; + v |= buf[4] >> 4; + H5 = (double)v; + H6 = (double)((signed char)buf[6]); + } + // configure buf[0] = 0xF5; // config buf[1] = 0x0C; // filter coefficient 8, spi off, duration 0 if ((status = dh_i2c_write(mAddress, buf, 2, 1)) != DH_I2C_OK) { - dhdebug("bmp280: failed to configure"); + dhdebug("bmx280: failed to configure"); return status; } buf[0] = 0xF4; // control buf[1] = 0xB7; // both oversampling to x16, normal mode if ((status = dh_i2c_write(mAddress, buf, 2, 1)) != DH_I2C_OK) { - dhdebug("bmp280: failed to control"); + dhdebug("bmx280: failed to control"); return status; } do { // wait until data is ready buf[0] = 0xF3; // status if ((status = dh_i2c_write(mAddress, buf, 1, 0)) != DH_I2C_OK) { - dhdebug("bmp280: failed to get status"); + dhdebug("bmx280: failed to get status"); return status; } if ((status = dh_i2c_read(mAddress, buf, 1)) != DH_I2C_OK) { - dhdebug("bmp280: failed to read status"); + dhdebug("bmx280: failed to read status"); return status; } } while (buf[0] & BIT(3)); buf[0] = 0xF7; // read press and temp result if ((status = dh_i2c_write(mAddress, buf, 1, 0)) != DH_I2C_OK) { - dhdebug("bmp280: failed to start reading"); + dhdebug("bmx280: failed to start reading"); return status; } if ((status = dh_i2c_read(mAddress, buf, 6)) != DH_I2C_OK) { - dhdebug("bmp280: failed to read"); + dhdebug("bmx280: failed to read"); return status; } buf[2] &= 0xF0; @@ -121,10 +152,32 @@ int ICACHE_FLASH_ATTR bmp280_read(int sda, int scl, float *pressure, float *temp p = p + (v1 + v2 + P7) / 16.0; *pressure = (float)p; + if (humidity) { + buf[0] = 0xFD; // read humidity + if ((status = dh_i2c_write(mAddress, buf, 1, 0)) != DH_I2C_OK) { + dhdebug("bmx280: failed to start reading humidity"); + return status; + } + if ((status = dh_i2c_read(mAddress, buf, 2)) != DH_I2C_OK) { + dhdebug("bmx280: failed to read humidity"); + return status; + } + double h = t_fine - 76800.0; + h = (signedInt16le(buf, 0) - (H4 * 64.0 + H5 / 16384.0 * h)) * \ + (H2 / 65536.0 * (1.0 + H6 / 67108864.0 * h * (1.0 + H3 / 67108864.0 * h))); + h = h * (1.0 - H1 * h / 524288.0); + if (h > 100.0) { + h = 100.0; + } else if (h < 0.0) { + h = 0.0; + } + *humidity = (float)h; + } + buf[0] = 0xF4; // control buf[1] = 0x0; // sleep mode if ((status = dh_i2c_write(mAddress, buf, 2, 1)) != DH_I2C_OK) { - dhdebug("bmp280: failed to shutdown"); + dhdebug("bmx280: failed to shutdown"); return status; } @@ -133,11 +186,11 @@ int ICACHE_FLASH_ATTR bmp280_read(int sda, int scl, float *pressure, float *temp /* - * bmp280_set_address() implementation. + * bmx280_set_address() implementation. */ -void ICACHE_FLASH_ATTR bmp280_set_address(int address) +void ICACHE_FLASH_ATTR bmx280_set_address(int address) { mAddress = address; } -#endif /* DH_DEVICE_BMP280 */ +#endif /* DH_DEVICE_BMX280 */ diff --git a/firmware-src/sources/devices/bmp280.h b/firmware-src/sources/devices/bmx280.h similarity index 60% rename from firmware-src/sources/devices/bmp280.h rename to firmware-src/sources/devices/bmx280.h index 2bf732f..7796b54 100644 --- a/firmware-src/sources/devices/bmp280.h +++ b/firmware-src/sources/devices/bmx280.h @@ -1,14 +1,14 @@ /** * @file - * @brief Simple communication with BMP280 pressure sensor. + * @brief Simple communication with BMP280 and BME280 sensors. * @copyright 2016 [DeviceHive](http://devicehive.com) * @author Nikolay Khabarov */ -#ifndef _DEVICES_BMP280_H_ -#define _DEVICES_BMP280_H_ +#ifndef _DEVICES_BMX280_H_ +#define _DEVICES_BMX280_H_ #include "user_config.h" -#if defined(DH_DEVICE_BMP280) +#if defined(DH_DEVICE_BMX280) /** * @brief Measure pressure one time. @@ -16,18 +16,20 @@ * @param[in] scl Pin for I2C's SCL. Can be DH_I2C_NO_PIN. * @param[out] pressure Pointer for storing pressure result measure in Pascals. * @param[out] temperature Pointer for storing temperature result measure in degree Celsius. Can be NULL. + * @param[out] humidity Pointer for storing humidity result measure in %RH. Can be NULL. * @return Status value, one of DH_I2C_Status enum. */ -int bmp280_read(int sda, int scl, +int bmx280_read(int sda, int scl, float *pressure, - float *temperature); + float *temperature, + float *humidity); /** * @brief Set sensor address which should be used while reading. * @param[in] address I2C end device address. */ -void bmp280_set_address(int address); +void bmx280_set_address(int address); -#endif /* DH_DEVICE_BMP280 */ -#endif /* _DEVICES_BMP280_H_ */ +#endif /* DH_DEVICE_BMX280 */ +#endif /* _DEVICES_BMX280_H_ */ diff --git a/firmware-src/sources/dhcommands.c b/firmware-src/sources/dhcommands.c index e2d42ee..954bc64 100644 --- a/firmware-src/sources/dhcommands.c +++ b/firmware-src/sources/dhcommands.c @@ -23,7 +23,6 @@ #include "commands/dht_cmd.h" #include "commands/ds18b20_cmd.h" #include "commands/bmp180_cmd.h" -#include "commands/bmp280_cmd.h" #include "commands/bh1750_cmd.h" #include "commands/mpu6050_cmd.h" #include "commands/hmc5883l_cmd.h" @@ -47,6 +46,7 @@ #include #include #include +#include "commands/bmx280_cmd.h" static void do_handle_command_list(COMMAND_RESULT *cmd_res, const char *command, const char *params, unsigned int params_len); @@ -115,8 +115,9 @@ RO_DATA struct { { "devices/bmp180/read", dh_handle_devices_bmp180_read}, #endif -#if defined(DH_COMMANDS_BMP280) && defined(DH_DEVICE_BMP280) +#if defined(DH_COMMANDS_BMX280) && defined(DH_DEVICE_BMX280) { "devices/bmp280/read", dh_handle_devices_bmp280_read}, + { "devices/bme280/read", dh_handle_devices_bme280_read}, #endif #if defined(DH_COMMANDS_BH1750) && defined(DH_DEVICE_BH1750) diff --git a/firmware-src/sources/user_config.h b/firmware-src/sources/user_config.h index 89dd192..6084441 100644 --- a/firmware-src/sources/user_config.h +++ b/firmware-src/sources/user_config.h @@ -42,7 +42,7 @@ #define DH_DEVICE_DHT11 #define DH_DEVICE_DHT22 #define DH_DEVICE_BMP180 -#define DH_DEVICE_BMP280 +#define DH_DEVICE_BMX280 #define DH_DEVICE_BH1750 #define DH_DEVICE_MPU6050 #define DH_DEVICE_HMC5883L @@ -68,7 +68,7 @@ #define DH_COMMANDS_DHT11 #define DH_COMMANDS_DHT22 #define DH_COMMANDS_BMP180 -#define DH_COMMANDS_BMP280 +#define DH_COMMANDS_BMX280 #define DH_COMMANDS_BH1750 #define DH_COMMANDS_MPU6050 #define DH_COMMANDS_HMC5883L