From 0f531e24e599690bc0db56d6ff27f7a6ba693599 Mon Sep 17 00:00:00 2001 From: arendst Date: Mon, 27 Nov 2017 17:46:51 +0100 Subject: [PATCH] v5.9.1j - Add Dual R2, Rewrite DS18x20 and fixes 5.9.1j * Revert changes to xsns_05_ds18x20.ino and rename to xsns_05_ds18x20_legacy.ino still needing library OneWire and providing legacy JSON message: * "DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}} * Add new xdrv_05_ds18x20.ino free from library OneWire and add the following features: * Add support for DS1822 * Add forced setting of 12-bit resolution for selected device types (#1222) * Add read temperature retry counter (#1215) * Fix lost sensors by performing sensor probe at restart only thereby removing dynamic sensor probe (#1215) * Fix sensor address sorting using ascending sort on sensor type followed by sensor address * Rewrite JSON resulting in shorter message allowing more sensors in default firmware image: * "DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6} * Add additional define in user_config.h to select either single sensor (defines disabled), new multi sensor (USE_DS18X20) or legacy multi sensor (USE_DS18X20_LEGACY) * Add support for Sonoff Dual R2 (#1249) * Fix ADS1115 detection (#1258) --- README.md | 2 +- platformio.ini | 2 +- sonoff/_releasenotes.ino | 20 +- sonoff/language/de-DE.h | 3 +- sonoff/language/en-GB.h | 3 +- sonoff/language/nl-NL.h | 3 +- sonoff/language/pl-PL.h | 3 +- sonoff/sonoff.ino | 2 +- sonoff/sonoff_post.h | 8 +- sonoff/sonoff_template.h | 17 ++ sonoff/support.ino | 141 +++++++----- sonoff/user_config.h | 4 +- sonoff/xsns_05_ds18b20.ino | 221 +++++++++--------- sonoff/xsns_05_ds18x20.ino | 358 +++++++++++++++++++++++------- sonoff/xsns_05_ds18x20_legacy.ino | 242 ++++++++++++++++++++ sonoff/xsns_12_ads1115.ino | 6 +- 16 files changed, 763 insertions(+), 272 deletions(-) create mode 100644 sonoff/xsns_05_ds18x20_legacy.ino diff --git a/README.md b/README.md index b13e41007..e451becff 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Sonoff-Tasmota Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. -Current version is **5.9.1i** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. +Current version is **5.9.1j** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/development/sonoff/_releasenotes.ino) for change information. ### ATTENTION All versions diff --git a/platformio.ini b/platformio.ini index 1c4479b18..a105642b9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -92,7 +92,7 @@ framework = arduino board = esp01_1m board_flash_mode = dout build_flags = -Wl,-Tesp8266.flash.1m0.ld -DMQTT_MAX_PACKET_SIZE=707 -DUSE_DS18x20 -DMESSZ=600 -lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON, OneWire +lib_deps = PubSubClient, NeoPixelBus, IRremoteESP8266, ArduinoJSON ; Serial Monitor options monitor_baud = 115200 diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index a4e5407a3..fc3b03f81 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,6 +1,24 @@ -/* 5.9.1i +/* 5.9.1j + * Revert changes to xsns_05_ds18x20.ino and rename to xsns_05_ds18x20_legacy.ino still needing library OneWire and providing legacy JSON message: + * "DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}} + * Add new xdrv_05_ds18x20.ino free from library OneWire and add the following features: + * Add support for DS1822 + * Add forced setting of 12-bit resolution for selected device types (#1222) + * Add read temperature retry counter (#1215) + * Fix lost sensors by performing sensor probe at restart only thereby removing dynamic sensor probe (#1215) + * Fix sensor address sorting using ascending sort on sensor type followed by sensor address + * Rewrite JSON resulting in shorter message allowing more sensors in default firmware image: + * "DS18B20-1":{"Id":"00000483C23A","Temperature":19.5},"DS18B20-2":{"Id":"0000048EC44C","Temperature":19.6} + * Add additional define in user_config.h to select either single sensor (defines disabled), new multi sensor (USE_DS18X20) or legacy multi sensor (USE_DS18X20_LEGACY) + * Add support for Sonoff Dual R2 (#1249) + * Fix ADS1115 detection (#1258) + * + * 5.9.1i * Fix Arilux LC11 restart exception 0 after OTA upgrade * Disabled CRC lookup-table in OneWire.h (#define ONEWIRE_CRC8_TABLE 0) to save some code space + * Change DS18x20 JSON message using less characters + * from "DS18x20":{"DS1":{"Type":"DS18B20","Address":"284CC48E04000079","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"283AC28304000052","Temperature":19.6}} + * into "DS18x20":{"DS1":{"Type":"DS18B20","Address":"0000048EC44C","Temperature":19.5},"DS2":{"Type":"DS18B20","Address":"00000483C23A","Temperature":19.6}} * Rewrite xsns_05_ds18x20.ino adding support for DS1822, correct address calculation and force setting 12-bit resolution (#1222) * DS18x20 sensor reconfiguration now only probed at restart removing dynamic connection and intermittent sensor loss (#1215) * diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index fcf345d67..1410ee50e 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -107,6 +107,7 @@ #define D_HOST "host" #define D_HOSTNAME "Hostname" #define D_HUMIDITY "Feuchtigkeit" +#define D_ID "ID" #define D_ILLUMINANCE "Beleuchtungsintensität" #define D_IMMEDIATE "direkt" // Button immediate #define D_INDEX "Index" @@ -437,7 +438,7 @@ #define D_ENERGY_YESTERDAY "Energie gestern" #define D_ENERGY_TOTAL "Energie insgesamt" -// xsns_05_ds18x20.ino +// xsns_05_ds18b20.ino #define D_SENSOR_BUSY "Sensor beschäftigt" #define D_SENSOR_CRC_ERROR "Sensor CRC-Fehler" #define D_SENSORS_FOUND "Sensor gefunden" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 5804fa947..0b3243f29 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -107,6 +107,7 @@ #define D_HOST "Host" #define D_HOSTNAME "Hostname" #define D_HUMIDITY "Humidity" +#define D_ID "Id" #define D_ILLUMINANCE "Illuminance" #define D_IMMEDIATE "immediate" // Button immediate #define D_INDEX "Index" @@ -437,7 +438,7 @@ #define D_ENERGY_YESTERDAY "Energy Yesterday" #define D_ENERGY_TOTAL "Energy Total" -// xsns_05_ds18x20.ino +// xsns_05_ds18b20.ino #define D_SENSOR_BUSY "Sensor busy" #define D_SENSOR_CRC_ERROR "Sensor CRC error" #define D_SENSORS_FOUND "Sensors found" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 9606da034..5147a7a97 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -107,6 +107,7 @@ #define D_HOST "Host" #define D_HOSTNAME "Hostnaam" #define D_HUMIDITY "Luchtvochtigheid" +#define D_ID "Id" #define D_ILLUMINANCE "Verlichtingssterkte" #define D_IMMEDIATE "onmiddelijk" // Button immediate #define D_INDEX "Index" @@ -437,7 +438,7 @@ #define D_ENERGY_YESTERDAY "Verbruik gisteren" #define D_ENERGY_TOTAL "Verbruik totaal" -// xsns_05_ds18x20.ino +// xsns_05_ds18b20.ino #define D_SENSOR_BUSY "Sensor bezet" #define D_SENSOR_CRC_ERROR "Sensor CRC fout" #define D_SENSORS_FOUND "Aantal sensoren" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 6ce3d108b..32710136b 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -107,6 +107,7 @@ #define D_HOST "Serwer" #define D_HOSTNAME "Nazwa serwera" #define D_HUMIDITY "Wilgotnosc" +#define D_ID "ID" #define D_ILLUMINANCE "Oswietlenie" #define D_IMMEDIATE "Natychmiastowe" // Button immediate #define D_INDEX "Indeks" @@ -437,7 +438,7 @@ #define D_ENERGY_YESTERDAY "Energia Wczoraj" #define D_ENERGY_TOTAL "Energia suma" -// xsns_05_ds18x20.ino +// xsns_05_ds18b20.ino #define D_SENSOR_BUSY "Czujnik DS18x20 zajety" #define D_SENSOR_CRC_ERROR "Czujnik DS18x20 blad CRC" #define D_SENSORS_FOUND "Znaleziono Czujnik DS18x20" diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index 29c2dca4c..9e713df5e 100644 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -25,7 +25,7 @@ - Select IDE Tools - Flash Size: "1M (no SPIFFS)" ====================================================*/ -#define VERSION 0x05090109 // 5.9.1i +#define VERSION 0x0509010A // 5.9.1j // Location specific includes #include "sonoff.h" // Enumaration used in user_config.h diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index 9f7259e54..93af8d3d6 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -34,9 +34,12 @@ void WifiWpsStatusCallback(wps_cb_status status); #endif #define USE_DHT // Default DHT11 sensor needs no external library -#ifndef USE_DS18x20 + +#if defined(USE_DS18x20) || defined(USE_DS18x20_LEGACY) +#else #define USE_DS18B20 // Default DS18B20 sensor needs no external library #endif + //#define DEBUG_THEO // Add debug code #ifdef BE_MINIMAL @@ -94,9 +97,8 @@ void WifiWpsStatusCallback(wps_cb_status status); #endif #ifndef MESSZ -#define MESSZ 405 // Max number of characters in JSON message string (4 x DS18x20 sensors) +#define MESSZ 405 // Max number of characters in JSON message string (6 x DS18x20 sensors) #endif - #endif // _SONOFF_POST_H_ \ No newline at end of file diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 3f858a67b..e7e1d6cbb 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -196,6 +196,7 @@ enum SupportedModules { KMC_70011, ARILUX_LC01, ARILUX_LC11, + SONOFF_DUAL_R2, MAXMODULE }; /********************************************************************************************/ @@ -218,6 +219,7 @@ const uint8_t kNiceList[MAXMODULE] PROGMEM = { SONOFF_RF, SONOFF_TH, SONOFF_DUAL, + SONOFF_DUAL_R2, SONOFF_POW, SONOFF_4CH, SONOFF_4CHPRO, @@ -761,6 +763,21 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { GPIO_PWM3, // GPIO14 RGB LED Blue GPIO_ARIRFRCV, // GPIO15 RF receiver input 0, 0 + }, + { "Sonoff Dual R2", // Sonoff Dual R2 (ESP8285) + GPIO_SWT1, // GPIO00 Button 1 on header + GPIO_USER, // GPIO01 Serial RXD and Optional sensor + 0, + GPIO_USER, // GPIO03 Serial TXD and Optional sensor + 0, + GPIO_REL2, // GPIO05 Relay 2 (0 = Off, 1 = On) + 0, 0, 0, // Flash connection + GPIO_SWT2, // GPIO09 Button 2 on header + GPIO_KEY1, // GPIO10 Button 3 on casing + 0, // Flash connection + GPIO_REL1, // GPIO12 Relay 1 (0 = Off, 1 = On) + GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) + 0, 0, 0, 0 } }; diff --git a/sonoff/support.ino b/sonoff/support.ino index 3ad2a54f3..cff8121f5 100644 --- a/sonoff/support.ino +++ b/sonoff/support.ino @@ -704,46 +704,95 @@ boolean MdnsDiscoverMqttServer() #ifdef USE_I2C #define I2C_RETRY_COUNTER 3 -int32_t I2cRead(uint8_t addr, uint8_t reg, uint8_t size) -{ - byte x = 0; - int32_t data = 0; +uint32_t i2c_buffer = 0; +bool I2cValidRead(uint8_t addr, uint8_t reg, uint8_t size) +{ + byte x = I2C_RETRY_COUNTER; + + i2c_buffer = 0; do { - Wire.beginTransmission(addr); // start transmission to device - Wire.write(reg); // sends register address to read from - if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... - Wire.requestFrom((int)addr, (int)size); // send data n-bytes read + Wire.beginTransmission(addr); // start transmission to device + Wire.write(reg); // sends register address to read from + if (0 == Wire.endTransmission(false)) { // Try to become I2C Master, send data and collect bytes, keep master status for next request... + Wire.requestFrom((int)addr, (int)size); // send data n-bytes read if (Wire.available() == size) { for (byte i = 0; i < size; i++) { - data <<= 8; - data |= Wire.read(); // receive DATA + i2c_buffer = i2c_buffer << 8 | Wire.read(); // receive DATA } } } - x++; - } while (Wire.endTransmission(true) != 0 && x <= I2C_RETRY_COUNTER); // end transmission - return data; + x--; + } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + return (x); +} + +bool I2cValidRead8(uint8_t *data, uint8_t addr, uint8_t reg) +{ + bool status = I2cValidRead(addr, reg, 1); + *data = (uint8_t)i2c_buffer; + return status; +} + +bool I2cValidRead16(uint16_t *data, uint8_t addr, uint8_t reg) +{ + bool status = I2cValidRead(addr, reg, 2); + *data = (uint16_t)i2c_buffer; + return status; +} + +bool I2cValidReadS16(int16_t *data, uint8_t addr, uint8_t reg) +{ + bool status = I2cValidRead(addr, reg, 2); + *data = (int16_t)i2c_buffer; + return status; +} + +bool I2cValidRead16LE(uint16_t *data, uint8_t addr, uint8_t reg) +{ + uint16_t ldata; + bool status = I2cValidRead16(&ldata, addr, reg); + *data = (ldata >> 8) | (ldata << 8); + return status; +} + +bool I2cValidReadS16_LE(int16_t *data, uint8_t addr, uint8_t reg) +{ + uint16_t ldata; + bool status = I2cValidRead16LE(&ldata, addr, reg); + *data = (int16_t)ldata; + return status; +} + +bool I2cValidRead24(int32_t *data, uint8_t addr, uint8_t reg) +{ + bool status = I2cValidRead(addr, reg, 3); + *data = i2c_buffer; + return status; } uint8_t I2cRead8(uint8_t addr, uint8_t reg) { - return I2cRead(addr, reg, 1); + I2cValidRead(addr, reg, 1); + return (uint8_t)i2c_buffer; } uint16_t I2cRead16(uint8_t addr, uint8_t reg) { - return I2cRead(addr, reg, 2); + I2cValidRead(addr, reg, 2); + return (uint16_t)i2c_buffer; } int16_t I2cReadS16(uint8_t addr, uint8_t reg) { - return (int16_t)I2cRead(addr, reg, 2); + I2cValidRead(addr, reg, 2); + return (int16_t)i2c_buffer; } uint16_t I2cRead16LE(uint8_t addr, uint8_t reg) { - uint16_t temp = I2cRead(addr, reg, 2); + I2cValidRead(addr, reg, 2); + uint16_t temp = (uint16_t)i2c_buffer; return (temp >> 8) | (temp << 8); } @@ -754,64 +803,34 @@ int16_t I2cReadS16_LE(uint8_t addr, uint8_t reg) int32_t I2cRead24(uint8_t addr, uint8_t reg) { - return I2cRead(addr, reg, 3); + I2cValidRead(addr, reg, 3); + return i2c_buffer; } -/* -void I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) -{ - byte x = I2C_RETRY_COUNTER; - int32_t data = val; - do { - Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(reg); // sends register address to read from - - for (byte i = 0; i < size; i++) { - - } - - Wire.write((val >> 8) & 0xFF); // write data - Wire.write(val); // write data - - x--; - } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission -} -*/ -void I2cWrite8v(uint8_t addr, uint8_t val) +bool I2cWrite(uint8_t addr, uint8_t reg, uint32_t val, uint8_t size) { byte x = I2C_RETRY_COUNTER; do { - Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(val); // write data + Wire.beginTransmission((uint8_t)addr); // start transmission to device + Wire.write(reg); // sends register address to write to + uint8_t loops = size -1; + do { + Wire.write((val >> (8 * loops)) & 0xFF); // write data + } while(--loops); x--; - } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + return (x); } -void I2cWrite8(uint8_t addr, uint8_t reg, uint8_t val) +bool I2cWrite8(uint8_t addr, uint8_t reg, uint16_t val) { - byte x = I2C_RETRY_COUNTER; - - do { - Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(reg); // sends register address to write to - Wire.write(val); // write data - x--; - } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission + return I2cWrite(addr, reg, val, 1); } bool I2cWrite16(uint8_t addr, uint8_t reg, uint16_t val) { - byte x = I2C_RETRY_COUNTER; - - do { - Wire.beginTransmission((uint8_t)addr); // start transmission to device - Wire.write(reg); // sends register address to write to - Wire.write((val >> 8) & 0xFF); // write data - Wire.write(val & 0xFF); // write data - x--; - } while (Wire.endTransmission(true) != 0 && x != 0); // end transmission - return (x); + return I2cWrite(addr, reg, val, 2); } void I2cScan(char *devs, unsigned int devs_len) diff --git a/sonoff/user_config.h b/sonoff/user_config.h index ac027e4a6..4314c045e 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -163,7 +163,9 @@ // -- Sensor code selection ----------------------- #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices -//#define USE_DS18x20 // Optional for more than one DS18B20 and/or DS18S20 sensors using library OneWire (+1.5k code) + // WARNING: Select none for default one sensor or enable one of the following two options for multiple sensors +//#define USE_DS18x20 // Optional for more than one DS18x20 sensors with id sort, single scan and read retry (+1.3k code) +//#define USE_DS18x20_LEGACY // Optional for more than one DS18B20 sensors using library OneWire (+1.5k code) #define USE_I2C // I2C using library wire (+10k code, 0.2k mem) - Disable by // #define USE_SHT // Add I2C emulating code for SHT1X sensor diff --git a/sonoff/xsns_05_ds18b20.ino b/sonoff/xsns_05_ds18b20.ino index 30fb23cc8..5c9ff013d 100644 --- a/sonoff/xsns_05_ds18b20.ino +++ b/sonoff/xsns_05_ds18b20.ino @@ -19,175 +19,177 @@ #ifdef USE_DS18B20 /*********************************************************************************************\ - * DS18B20 - Temperature - * - * Source: Marinus vd Broek https://github.com/ESP8266nu/ESPEasy and AlexTransit (CRC) + * DS18B20 - Temperature - Single sensor \*********************************************************************************************/ +#define W1_SKIP_ROM 0xCC +#define W1_CONVERT_TEMP 0x44 +#define W1_READ_SCRATCHPAD 0xBE + float ds18b20_last_temperature = 0; uint16_t ds18b20_last_result = 0; +uint8_t ds18x20_pin = 0; -uint8_t Ds18b20Reset() +/*********************************************************************************************\ + * Embedded stripped and tuned OneWire library +\*********************************************************************************************/ + +uint8_t OneWireReset() { - uint8_t r; uint8_t retries = 125; - pinMode(pin[GPIO_DSB], INPUT); - do { // wait until the wire is high... just in case + //noInterrupts(); + pinMode(ds18x20_pin, INPUT); + do { if (--retries == 0) { return 0; } delayMicroseconds(2); - } while (!digitalRead(pin[GPIO_DSB])); - pinMode(pin[GPIO_DSB], OUTPUT); - digitalWrite(pin[GPIO_DSB], LOW); - delayMicroseconds(492); // Dallas spec. = Min. 480uSec. Arduino 500uSec. - pinMode(pin[GPIO_DSB], INPUT); // Float - delayMicroseconds(40); - r = !digitalRead(pin[GPIO_DSB]); - delayMicroseconds(420); + } while (!digitalRead(ds18x20_pin)); + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); + delayMicroseconds(480); + pinMode(ds18x20_pin, INPUT); + delayMicroseconds(70); + uint8_t r = !digitalRead(ds18x20_pin); + //interrupts(); + delayMicroseconds(410); return r; } -uint8_t Ds18b20ReadBit(void) +void OneWireWriteBit(uint8_t v) { - uint8_t r; + static const uint8_t delay_low[2] = { 65, 10 }; + static const uint8_t delay_high[2] = { 5, 55 }; - pinMode(pin[GPIO_DSB], OUTPUT); - digitalWrite(pin[GPIO_DSB], LOW); + v &= 1; + //noInterrupts(); + digitalWrite(ds18x20_pin, LOW); + pinMode(ds18x20_pin, OUTPUT); + delayMicroseconds(delay_low[v]); + digitalWrite(ds18x20_pin, HIGH); + //interrupts(); + delayMicroseconds(delay_high[v]); +} + +uint8_t OneWireReadBit() +{ + //noInterrupts(); + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); delayMicroseconds(3); - pinMode(pin[GPIO_DSB], INPUT); // let pin float, pull up will raise + pinMode(ds18x20_pin, INPUT); delayMicroseconds(10); - r = digitalRead(pin[GPIO_DSB]); + uint8_t r = digitalRead(ds18x20_pin); + //interrupts(); delayMicroseconds(53); return r; } -uint8_t Ds18b20Read(void) +void OneWireWrite(uint8_t v) +{ + for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { + OneWireWriteBit((bit_mask & v) ? 1 : 0); + } +} + +uint8_t OneWireRead() { - uint8_t bit_mask; uint8_t r = 0; - for (bit_mask = 1; bit_mask; bit_mask <<= 1) { - if (Ds18b20ReadBit()) { + for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { + if (OneWireReadBit()) { r |= bit_mask; } } return r; } -void Ds18b20WriteBit(uint8_t v) +boolean OneWireCrc8(uint8_t *addr) { - if (v & 1) { - digitalWrite(pin[GPIO_DSB], LOW); - pinMode(pin[GPIO_DSB], OUTPUT); - delayMicroseconds(10); - digitalWrite(pin[GPIO_DSB], HIGH); - delayMicroseconds(55); - } else { - digitalWrite(pin[GPIO_DSB], LOW); - pinMode(pin[GPIO_DSB], OUTPUT); - delayMicroseconds(65); - digitalWrite(pin[GPIO_DSB], HIGH); - delayMicroseconds(5); + uint8_t crc = 0; + uint8_t len = 8; + + while (len--) { + uint8_t inbyte = *addr++; // from 0 to 7 + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) { + crc ^= 0x8C; + } + inbyte >>= 1; + } } + return (crc == *addr); // addr 8 } -void Ds18b20Write(uint8_t byte_to_write) -{ - uint8_t bit_mask; +/********************************************************************************************/ - for (bit_mask = 1; bit_mask; bit_mask <<= 1) { - Ds18b20WriteBit((bit_mask & byte_to_write) ? 1 : 0); - } +void Ds18x20Init() +{ + ds18x20_pin = pin[GPIO_DSB]; } -uint8 Ds18b20Crc(uint8 inp, uint8 crc) +void Ds18x20Convert() { - inp ^= crc; - crc = 0; - if (inp & 0x1) crc ^= 0x5e; - if (inp & 0x2) crc ^= 0xbc; - if (inp & 0x4) crc ^= 0x61; - if (inp & 0x8) crc ^= 0xc2; - if (inp & 0x10) crc ^= 0x9d; - if (inp & 0x20) crc ^= 0x23; - if (inp & 0x40) crc ^= 0x46; - if (inp & 0x80) crc ^= 0x8c; - return crc; + OneWireReset(); + OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus + OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end +// delay(750); // 750ms should be enough for 12bit conv } -void Ds18b20ReadTempPrep() +boolean Ds18b20Read(float &t) { - Ds18b20Reset(); - Ds18b20Write(0xCC); // Skip ROM - Ds18b20Write(0x44); // Start conversion -} - -boolean Ds18b20ReadTemperature(float &t) -{ - int16_t DSTemp; - byte msb, lsb, crc, sign = 1; + uint8_t data[9]; + int8_t sign = 1; if (!ds18b20_last_temperature) { t = NAN; } else { ds18b20_last_result++; - if (ds18b20_last_result > 8) { // Reset after 8 misses + if (ds18b20_last_result > 4) { // Reset after 4 misses ds18b20_last_temperature = NAN; } t = ds18b20_last_temperature; } - if (!Ds18b20ReadBit()) { //check measurement end +/* + if (!OneWireReadBit()) { //check measurement end AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_BUSY)); return !isnan(t); } -/* - Ds18b20Reset(); - Ds18b20Write(0xCC); // Skip ROM - Ds18b20Write(0x44); // Start conversion - delay(800); */ - Ds18b20Reset(); - Ds18b20Write(0xCC); // Skip ROM - Ds18b20Write(0xBE); // Read scratchpad - lsb = Ds18b20Read(); - msb = Ds18b20Read(); - crc = Ds18b20Crc(lsb, crc); - crc = Ds18b20Crc(msb, crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - crc = Ds18b20Crc(Ds18b20Read(), crc); - Ds18b20Reset(); - if (crc) { //check crc - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); - } else { - DSTemp = (msb << 8) + lsb; - if (DSTemp > 2047) { - DSTemp = (~DSTemp) +1; - sign = -1; + for (uint8_t retry = 0; retry < 3; retry++) { + OneWireReset(); + OneWireWrite(W1_SKIP_ROM); + OneWireWrite(W1_READ_SCRATCHPAD); + for (uint8_t i = 0; i < 9; i++) { + data[i] = OneWireRead(); + } + if (OneWireCrc8(data)) { + uint16_t temp12 = (data[1] << 8) + data[0]; + if (temp12 > 2047) { + temp12 = (~temp12) +1; + sign = -1; + } + t = ConvertTemp(sign * temp12 * 0.0625); + ds18b20_last_result = 0; + } + if (!isnan(t)) { + ds18b20_last_temperature = t; + return true; } - t = ConvertTemp((float)sign * DSTemp * 0.0625); - ds18b20_last_result = 0; - } - if (!isnan(t)) { - ds18b20_last_temperature = t; } + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); return !isnan(t); } -/********************************************************************************************/ - void Ds18b20Show(boolean json) { float t; - if (Ds18b20ReadTemperature(t)) { // Check if read failed + if (Ds18b20Read(t)) { // Check if read failed char temperature[10]; dtostrfi(t, Settings.flag2.temperature_resolution, temperature); @@ -203,11 +205,6 @@ void Ds18b20Show(boolean json) #endif // USE_WEBSERVER } } -#ifdef USE_WEBSERVER - if (!json) { - Ds18b20ReadTempPrep(); - } -#endif // USE_WEBSERVER } /*********************************************************************************************\ @@ -222,10 +219,11 @@ boolean Xsns05(byte function) if (pin[GPIO_DSB] < 99) { switch (function) { -// case FUNC_XSNS_INIT: -// break; + case FUNC_XSNS_INIT: + Ds18x20Init(); + break; case FUNC_XSNS_PREP: - Ds18b20ReadTempPrep(); + Ds18x20Convert(); // Start conversion, takes up to one second break; case FUNC_XSNS_JSON_APPEND: Ds18b20Show(1); @@ -233,6 +231,7 @@ boolean Xsns05(byte function) #ifdef USE_WEBSERVER case FUNC_XSNS_WEB: Ds18b20Show(0); + Ds18x20Convert(); // Start conversion, takes up to one second break; #endif // USE_WEBSERVER } diff --git a/sonoff/xsns_05_ds18x20.ino b/sonoff/xsns_05_ds18x20.ino index abf2d4d8d..de334b4d2 100644 --- a/sonoff/xsns_05_ds18x20.ino +++ b/sonoff/xsns_05_ds18x20.ino @@ -1,7 +1,7 @@ /* xsns_05_ds18x20.ino - DS18x20 temperature sensor support for Sonoff-Tasmota - Copyright (C) 2017 Heiko Krupp and Theo Arends + Copyright (C) 2017 Theo Arends This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,7 +19,7 @@ #ifdef USE_DS18x20 /*********************************************************************************************\ - * DS18B20 - Temperature + * DS18B20 - Temperature - Multiple sensors \*********************************************************************************************/ #define DS18S20_CHIPID 0x10 // +/-0.5C 9-bit @@ -37,37 +37,236 @@ const char kDs18x20Types[] PROGMEM = "DS18x20|DS18S20|DS1822|DS18B20|MAX31850"; -#include - -OneWire *ds = NULL; - uint8_t ds18x20_chipids[] = { 0, DS18S20_CHIPID, DS1822_CHIPID, DS18B20_CHIPID, MAX31850_CHIPID }; uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8]; uint8_t ds18x20_index[DS18X20_MAX_SENSORS] = { 0 }; uint8_t ds18x20_sensors = 0; +uint8_t ds18x20_pin = 0; char ds18x20_types[9]; +/*********************************************************************************************\ + * Embedded tuned OneWire library +\*********************************************************************************************/ + +#define W1_MATCH_ROM 0x55 +#define W1_SEARCH_ROM 0xF0 + +uint8_t onewire_last_discrepancy = 0; +uint8_t onewire_last_family_discrepancy = 0; +bool onewire_last_device_flag = false; +unsigned char onewire_rom_id[8] = { 0 }; + +uint8_t OneWireReset() +{ + uint8_t retries = 125; + + //noInterrupts(); + pinMode(ds18x20_pin, INPUT); + do { + if (--retries == 0) { + return 0; + } + delayMicroseconds(2); + } while (!digitalRead(ds18x20_pin)); + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); + delayMicroseconds(480); + pinMode(ds18x20_pin, INPUT); + delayMicroseconds(70); + uint8_t r = !digitalRead(ds18x20_pin); + //interrupts(); + delayMicroseconds(410); + return r; +} + +void OneWireWriteBit(uint8_t v) +{ + static const uint8_t delay_low[2] = { 65, 10 }; + static const uint8_t delay_high[2] = { 5, 55 }; + + v &= 1; + //noInterrupts(); + digitalWrite(ds18x20_pin, LOW); + pinMode(ds18x20_pin, OUTPUT); + delayMicroseconds(delay_low[v]); + digitalWrite(ds18x20_pin, HIGH); + //interrupts(); + delayMicroseconds(delay_high[v]); +} + +uint8_t OneWireReadBit() +{ + //noInterrupts(); + pinMode(ds18x20_pin, OUTPUT); + digitalWrite(ds18x20_pin, LOW); + delayMicroseconds(3); + pinMode(ds18x20_pin, INPUT); + delayMicroseconds(10); + uint8_t r = digitalRead(ds18x20_pin); + //interrupts(); + delayMicroseconds(53); + return r; +} + +void OneWireWrite(uint8_t v) +{ + for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { + OneWireWriteBit((bit_mask & v) ? 1 : 0); + } +} + +uint8_t OneWireRead() +{ + uint8_t r = 0; + + for (uint8_t bit_mask = 0x01; bit_mask; bit_mask <<= 1) { + if (OneWireReadBit()) { + r |= bit_mask; + } + } + return r; +} + +void OneWireSelect(const uint8_t rom[8]) +{ + OneWireWrite(W1_MATCH_ROM); + for (uint8_t i = 0; i < 8; i++) { + OneWireWrite(rom[i]); + } +} + +void OneWireResetSearch() +{ + onewire_last_discrepancy = 0; + onewire_last_device_flag = false; + onewire_last_family_discrepancy = 0; + for (uint8_t i = 0; i < 8; i++) { + onewire_rom_id[i] = 0; + } +} + +uint8_t OneWireSearch(uint8_t *newAddr) +{ + uint8_t id_bit_number = 1; + uint8_t last_zero = 0; + uint8_t rom_byte_number = 0; + uint8_t search_result = 0; + uint8_t id_bit; + uint8_t cmp_id_bit; + unsigned char rom_byte_mask = 1; + unsigned char search_direction; + + if (!onewire_last_device_flag) { + if (!OneWireReset()) { + onewire_last_discrepancy = 0; + onewire_last_device_flag = false; + onewire_last_family_discrepancy = 0; + return false; + } + OneWireWrite(W1_SEARCH_ROM); + do { + id_bit = OneWireReadBit(); + cmp_id_bit = OneWireReadBit(); + + if ((id_bit == 1) && (cmp_id_bit == 1)) { + break; + } else { + if (id_bit != cmp_id_bit) { + search_direction = id_bit; + } else { + if (id_bit_number < onewire_last_discrepancy) { + search_direction = ((onewire_rom_id[rom_byte_number] & rom_byte_mask) > 0); + } else { + search_direction = (id_bit_number == onewire_last_discrepancy); + } + if (search_direction == 0) { + last_zero = id_bit_number; + if (last_zero < 9) { + onewire_last_family_discrepancy = last_zero; + } + } + } + if (search_direction == 1) { + onewire_rom_id[rom_byte_number] |= rom_byte_mask; + } else { + onewire_rom_id[rom_byte_number] &= ~rom_byte_mask; + } + OneWireWriteBit(search_direction); + id_bit_number++; + rom_byte_mask <<= 1; + if (rom_byte_mask == 0) { + rom_byte_number++; + rom_byte_mask = 1; + } + } + } while (rom_byte_number < 8); + if (!(id_bit_number < 65)) { + onewire_last_discrepancy = last_zero; + if (onewire_last_discrepancy == 0) { + onewire_last_device_flag = true; + } + search_result = true; + } + } + if (!search_result || !onewire_rom_id[0]) { + onewire_last_discrepancy = 0; + onewire_last_device_flag = false; + onewire_last_family_discrepancy = 0; + search_result = false; + } + for (uint8_t i = 0; i < 8; i++) { + newAddr[i] = onewire_rom_id[i]; + } + return search_result; +} + +boolean OneWireCrc8(uint8_t *addr) +{ + uint8_t crc = 0; + uint8_t len = 8; + + while (len--) { + uint8_t inbyte = *addr++; // from 0 to 7 + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) { + crc ^= 0x8C; + } + inbyte >>= 1; + } + } + return (crc == *addr); // addr 8 +} + +/********************************************************************************************/ + void Ds18x20Init() { - ds = new OneWire(pin[GPIO_DSB]); - ds->reset_search(); + uint64_t ids[DS18X20_MAX_SENSORS]; + + ds18x20_pin = pin[GPIO_DSB]; + OneWireResetSearch(); for (ds18x20_sensors = 0; ds18x20_sensors < DS18X20_MAX_SENSORS; ds18x20_sensors) { - if (!ds->search(ds18x20_address[ds18x20_sensors])) { - ds->reset_search(); + if (!OneWireSearch(ds18x20_address[ds18x20_sensors])) { break; } - if ((OneWire::crc8(ds18x20_address[ds18x20_sensors], 7) == ds18x20_address[ds18x20_sensors][7]) && + if (OneWireCrc8(ds18x20_address[ds18x20_sensors]) && ((ds18x20_address[ds18x20_sensors][0] == DS18S20_CHIPID) || (ds18x20_address[ds18x20_sensors][0] == DS1822_CHIPID) || (ds18x20_address[ds18x20_sensors][0] == DS18B20_CHIPID) || (ds18x20_address[ds18x20_sensors][0] == MAX31850_CHIPID))) { ds18x20_index[ds18x20_sensors] = ds18x20_sensors; + ids[ds18x20_sensors] = ds18x20_address[ds18x20_sensors][0]; // Chip id + for (uint8_t j = 6; j > 0; j--) { + ids[ds18x20_sensors] = ids[ds18x20_sensors] << 8 | ds18x20_address[ds18x20_sensors][j]; + } ds18x20_sensors++; } } - for (byte i = 0; i < ds18x20_sensors; i++) { - for (byte j = i + 1; j < ds18x20_sensors; j++) { - if (uint32_t(ds18x20_address[ds18x20_index[i]]) > uint32_t(ds18x20_address[ds18x20_index[j]])) { + for (uint8_t i = 0; i < ds18x20_sensors; i++) { + for (uint8_t j = i + 1; j < ds18x20_sensors; j++) { + if (ids[ds18x20_index[i]] > ids[ds18x20_index[j]]) { // Sort ascending std::swap(ds18x20_index[i], ds18x20_index[j]); } } @@ -78,81 +277,80 @@ void Ds18x20Init() void Ds18x20Convert() { - ds->reset(); - ds->write(W1_SKIP_ROM); // Address all Sensors on Bus - ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end -// delay(750); // 750ms should be enough for 12bit conv + OneWireReset(); + OneWireWrite(W1_SKIP_ROM); // Address all Sensors on Bus + OneWireWrite(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end +// delay(750); // 750ms should be enough for 12bit conv } boolean Ds18x20Read(uint8_t sensor, float &t) { - byte data[12]; + uint8_t data[9]; int8_t sign = 1; float temp9 = 0.0; - uint8_t present = 0; t = NAN; - ds->reset(); - ds->select(ds18x20_address[ds18x20_index[sensor]]); - ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad - - for (byte i = 0; i < 9; i++) { - data[i] = ds->read(); - } - if (OneWire::crc8(data, 8) == data[8]) { - switch(ds18x20_address[ds18x20_index[sensor]][0]) { - case DS18S20_CHIPID: - if (data[1] > 0x80) { - data[0] = (~data[0]) +1; - sign = -1; // App-Note fix possible sign error - } - if (data[0] & 1) { - temp9 = ((data[0] >> 1) + 0.5) * sign; - } else { - temp9 = (data[0] >> 1) * sign; - } - t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); - break; - case DS1822_CHIPID: - case DS18B20_CHIPID: - if (data[4] != 0x7F) { - data[4] = 0x7F; // Set resolution to 12-bit - ds->reset(); - ds->select(ds18x20_address[ds18x20_index[sensor]]); - ds->write(W1_WRITE_SCRATCHPAD); // Write Scratchpad - ds->write(data[2]); // Th Register - ds->write(data[3]); // Tl Register - ds->write(data[4]); // Configuration Register - ds->select(ds18x20_address[ds18x20_index[sensor]]); - ds->write(W1_WRITE_EEPROM); // Save scratchpad to EEPROM - } - case MAX31850_CHIPID: - uint16_t temp12 = (data[1] << 8) + data[0]; - if (temp12 > 2047) { - temp12 = (~temp12) +1; - sign = -1; - } - t = ConvertTemp(sign * temp12 * 0.0625); - break; + for (uint8_t retry = 0; retry < 3; retry++) { + OneWireReset(); + OneWireSelect(ds18x20_address[ds18x20_index[sensor]]); + OneWireWrite(W1_READ_SCRATCHPAD); + for (uint8_t i = 0; i < 9; i++) { + data[i] = OneWireRead(); + } + if (OneWireCrc8(data)) { + switch(ds18x20_address[ds18x20_index[sensor]][0]) { + case DS18S20_CHIPID: + if (data[1] > 0x80) { + data[0] = (~data[0]) +1; + sign = -1; // App-Note fix possible sign error + } + if (data[0] & 1) { + temp9 = ((data[0] >> 1) + 0.5) * sign; + } else { + temp9 = (data[0] >> 1) * sign; + } + t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); + break; + case DS1822_CHIPID: + case DS18B20_CHIPID: + if (data[4] != 0x7F) { + data[4] = 0x7F; // Set resolution to 12-bit + OneWireReset(); + OneWireSelect(ds18x20_address[ds18x20_index[sensor]]); + OneWireWrite(W1_WRITE_SCRATCHPAD); + OneWireWrite(data[2]); // Th Register + OneWireWrite(data[3]); // Tl Register + OneWireWrite(data[4]); // Configuration Register + OneWireSelect(ds18x20_address[ds18x20_index[sensor]]); + OneWireWrite(W1_WRITE_EEPROM); // Save scratchpad to EEPROM + } + case MAX31850_CHIPID: + uint16_t temp12 = (data[1] << 8) + data[0]; + if (temp12 > 2047) { + temp12 = (~temp12) +1; + sign = -1; + } + t = ConvertTemp(sign * temp12 * 0.0625); + break; + } + } + if (!isnan(t)) { + return true; } - } else { - AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); } - return (!isnan(t)); + AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DSB D_SENSOR_CRC_ERROR)); + return false; } -/********************************************************************************************/ - void Ds18x20Show(boolean json) { char temperature[10]; char stemp[12]; - char separator[2] = { '\0' }; float t; bool domoticz_flag = true; - for (byte i = 0; i < ds18x20_sensors; i++) { + for (uint8_t i = 0; i < ds18x20_sensors; i++) { if (Ds18x20Read(i, t)) { // Check if read failed dtostrfd(t, Settings.flag2.temperature_resolution, temperature); @@ -164,23 +362,17 @@ void Ds18x20Show(boolean json) index--; } GetTextIndexed(ds18x20_types, sizeof(ds18x20_types), index, kDs18x20Types); + + snprintf_P(stemp, sizeof(stemp), PSTR("%s-%d"), ds18x20_types, i +1); if (json) { if (1 == ds18x20_sensors) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_TEMPERATURE "\":%s}"), mqtt_data, ds18x20_types, temperature); } else { char address[17]; -// for (byte j = 0; j < 8; j++) { -// sprintf(address+2*j, "%02X", ds18x20_address[ds18x20_index[i]][j]); -// } for (byte j = 0; j < 6; j++) { sprintf(address+2*j, "%02X", ds18x20_address[ds18x20_index[i]][6-j]); // Skip sensor type and crc } - if (!separator[0]) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18x20\":{"), mqtt_data); - } - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"DS%d\":{\"" D_TYPE "\":\"%s\",\"" D_ADDRESS "\":\"%s\",\"" D_TEMPERATURE "\":%s}"), - mqtt_data, separator, i +1, ds18x20_types, address, temperature); - separator[0] = ','; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_ID "\":\"%s\",\"" D_TEMPERATURE "\":%s}"), mqtt_data, stemp, address, temperature); } #ifdef USE_DOMOTICZ if (domoticz_flag) { @@ -190,17 +382,11 @@ void Ds18x20Show(boolean json) #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER } else { - snprintf_P(stemp, sizeof(stemp), PSTR("%s-%d"), ds18x20_types, i +1); snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, (1 == ds18x20_sensors) ? ds18x20_types : stemp, temperature, TempUnit()); #endif // USE_WEBSERVER } } } - if (json) { - if (separator[0]) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); - } - } } /*********************************************************************************************\ @@ -219,7 +405,7 @@ boolean Xsns05(byte function) Ds18x20Init(); break; case FUNC_XSNS_PREP: - Ds18x20Convert(); // Check for changes in sensor number and start conversion, takes up to one second + Ds18x20Convert(); // Start conversion, takes up to one second break; case FUNC_XSNS_JSON_APPEND: Ds18x20Show(1); @@ -227,7 +413,7 @@ boolean Xsns05(byte function) #ifdef USE_WEBSERVER case FUNC_XSNS_WEB: Ds18x20Show(0); - Ds18x20Convert(); // Check for changes in sensor number and start conversion, takes up to one second + Ds18x20Convert(); // Start conversion, takes up to one second break; #endif // USE_WEBSERVER } diff --git a/sonoff/xsns_05_ds18x20_legacy.ino b/sonoff/xsns_05_ds18x20_legacy.ino new file mode 100644 index 000000000..beffe780d --- /dev/null +++ b/sonoff/xsns_05_ds18x20_legacy.ino @@ -0,0 +1,242 @@ +/* + xsns_05_ds18x20_legacy.ino - DS18x20 temperature sensor support for Sonoff-Tasmota + + Copyright (C) 2017 Heiko Krupp and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_DS18x20_LEGACY +/*********************************************************************************************\ + * DS18B20 - Temperature +\*********************************************************************************************/ + +#define DS18S20_CHIPID 0x10 +#define DS18B20_CHIPID 0x28 +#define MAX31850_CHIPID 0x3B + +#define W1_SKIP_ROM 0xCC +#define W1_CONVERT_TEMP 0x44 +#define W1_READ_SCRATCHPAD 0xBE + +#define DS18X20_MAX_SENSORS 8 + +#include + +OneWire *ds = NULL; + +uint8_t ds18x20_address[DS18X20_MAX_SENSORS][8]; +uint8_t ds18x20_index[DS18X20_MAX_SENSORS]; +uint8_t ds18x20_sensors = 0; +char ds18x20_types[9]; + +void Ds18x20Init() +{ + ds = new OneWire(pin[GPIO_DSB]); +} + +void Ds18x20Search() +{ + uint8_t num_sensors=0; + uint8_t sensor = 0; + + ds->reset_search(); + for (num_sensors = 0; num_sensors < DS18X20_MAX_SENSORS; num_sensors) { + if (!ds->search(ds18x20_address[num_sensors])) { + ds->reset_search(); + break; + } + // If CRC Ok and Type DS18S20, DS18B20 or MAX31850 + if ((OneWire::crc8(ds18x20_address[num_sensors], 7) == ds18x20_address[num_sensors][7]) && + ((ds18x20_address[num_sensors][0]==DS18S20_CHIPID) || (ds18x20_address[num_sensors][0]==DS18B20_CHIPID) || (ds18x20_address[num_sensors][0]==MAX31850_CHIPID))) { + num_sensors++; + } + } + for (byte i = 0; i < num_sensors; i++) { + ds18x20_index[i] = i; + } + for (byte i = 0; i < num_sensors; i++) { + for (byte j = i + 1; j < num_sensors; j++) { + if (uint32_t(ds18x20_address[ds18x20_index[i]]) > uint32_t(ds18x20_address[ds18x20_index[j]])) { + std::swap(ds18x20_index[i], ds18x20_index[j]); + } + } + } + ds18x20_sensors = num_sensors; +} + +uint8_t Ds18x20Sensors() +{ + return ds18x20_sensors; +} + +String Ds18x20Addresses(uint8_t sensor) +{ + char address[20]; + + for (byte i = 0; i < 8; i++) { + sprintf(address+2*i, "%02X", ds18x20_address[ds18x20_index[sensor]][i]); + } + return String(address); +} + +void Ds18x20Convert() +{ + ds->reset(); + ds->write(W1_SKIP_ROM); // Address all Sensors on Bus + ds->write(W1_CONVERT_TEMP); // start conversion, no parasite power on at the end +// delay(750); // 750ms should be enough for 12bit conv +} + +boolean Ds18x20Read(uint8_t sensor, float &t) +{ + byte data[12]; + int8_t sign = 1; + float temp9 = 0.0; + uint8_t present = 0; + + t = NAN; + + ds->reset(); + ds->select(ds18x20_address[ds18x20_index[sensor]]); + ds->write(W1_READ_SCRATCHPAD); // Read Scratchpad + + for (byte i = 0; i < 9; i++) { + data[i] = ds->read(); + } + if (OneWire::crc8(data, 8) == data[8]) { + switch(ds18x20_address[ds18x20_index[sensor]][0]) { + case DS18S20_CHIPID: // DS18S20 + if (data[1] > 0x80) { + data[0] = (~data[0]) +1; + sign = -1; // App-Note fix possible sign error + } + if (data[0] & 1) { + temp9 = ((data[0] >> 1) + 0.5) * sign; + } else { + temp9 = (data[0] >> 1) * sign; + } + t = ConvertTemp((temp9 - 0.25) + ((16.0 - data[6]) / 16.0)); + break; + case DS18B20_CHIPID: // DS18B20 + case MAX31850_CHIPID: // MAX31850 + uint16_t temp12 = (data[1] << 8) + data[0]; + if (temp12 > 2047) { + temp12 = (~temp12) +1; + sign = -1; + } + t = ConvertTemp(sign * temp12 * 0.0625); + break; + } + } + return (!isnan(t)); +} + +/********************************************************************************************/ + +void Ds18x20Type(uint8_t sensor) +{ + strcpy_P(ds18x20_types, PSTR("DS18x20")); + switch(ds18x20_address[ds18x20_index[sensor]][0]) { + case DS18S20_CHIPID: + strcpy_P(ds18x20_types, PSTR("DS18S20")); + break; + case DS18B20_CHIPID: + strcpy_P(ds18x20_types, PSTR("DS18B20")); + break; + case MAX31850_CHIPID: + strcpy_P(ds18x20_types, PSTR("MAX31850")); + break; + } +} + +void Ds18x20Show(boolean json) +{ + char temperature[10]; + char stemp[10]; + float t; + + byte dsxflg = 0; + for (byte i = 0; i < Ds18x20Sensors(); i++) { + if (Ds18x20Read(i, t)) { // Check if read failed + Ds18x20Type(i); + dtostrfd(t, Settings.flag2.temperature_resolution, temperature); + + if (json) { + if (!dsxflg) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"DS18x20\":{"), mqtt_data); + stemp[0] = '\0'; + } + dsxflg++; + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%s\"DS%d\":{\"" D_TYPE "\":\"%s\",\"" D_ADDRESS "\":\"%s\",\"" D_TEMPERATURE "\":%s}"), + mqtt_data, stemp, i +1, ds18x20_types, Ds18x20Addresses(i).c_str(), temperature); + strcpy(stemp, ","); +#ifdef USE_DOMOTICZ + if (1 == dsxflg) { + DomoticzSensor(DZ_TEMP, temperature); + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + snprintf_P(stemp, sizeof(stemp), PSTR("%s-%d"), ds18x20_types, i +1); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, stemp, temperature, TempUnit()); +#endif // USE_WEBSERVER + } + } + } + if (json) { + if (dsxflg) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}"), mqtt_data); + } +#ifdef USE_WEBSERVER + } else { + Ds18x20Search(); // Check for changes in sensors number + Ds18x20Convert(); // Start Conversion, takes up to one second +#endif // USE_WEBSERVER + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_05 + +boolean Xsns05(byte function) +{ + boolean result = false; + + if (pin[GPIO_DSB] < 99) { + switch (function) { + case FUNC_XSNS_INIT: + Ds18x20Init(); + break; + case FUNC_XSNS_PREP: + Ds18x20Search(); // Check for changes in sensors number + Ds18x20Convert(); // Start Conversion, takes up to one second + break; + case FUNC_XSNS_JSON_APPEND: + Ds18x20Show(1); + break; +#ifdef USE_WEBSERVER + case FUNC_XSNS_WEB: + Ds18x20Show(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_DS18x20_LEGACY diff --git a/sonoff/xsns_12_ads1115.ino b/sonoff/xsns_12_ads1115.ino index f4682de44..ffe5c5eca 100644 --- a/sonoff/xsns_12_ads1115.ino +++ b/sonoff/xsns_12_ads1115.ino @@ -133,7 +133,7 @@ void Ads1115StartComparator(uint8_t channel, uint16_t mode) // Set single-ended input channel config |= (ADS1115_REG_CONFIG_MUX_SINGLE_0 + (0x1000 * channel)); - + // Write config register to the ADC I2cWrite16(ads1115_address, ADS1115_REG_POINTER_CONFIG, config); } @@ -157,13 +157,15 @@ int16_t Ads1115GetConversion(uint8_t channel) void Ads1115Detect() { + uint16_t buffer; + if (ads1115_type) { return; } for (byte i = 0; i < sizeof(ads1115_addresses); i++) { ads1115_address = ads1115_addresses[i]; - if (I2cRead16(ads1115_address, ADS1115_REG_POINTER_CONVERT)) { + if (I2cValidRead16(&buffer, ads1115_address, ADS1115_REG_POINTER_CONVERT)) { Ads1115StartComparator(i, ADS1115_REG_CONFIG_MODE_CONTIN); ads1115_type = 1; break;