From a02c733073696a4442bd84b9f697e646f7edd737 Mon Sep 17 00:00:00 2001 From: Staars Date: Tue, 17 Sep 2019 22:03:30 +0200 Subject: [PATCH 1/6] enable slow reads for original CHIRP-sensor --- sonoff/xsns_48_chirp.ino | 829 ++++++++++++++++++++++----------------- 1 file changed, 459 insertions(+), 370 deletions(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index f0948a5a2..c54c10878 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -1,482 +1,571 @@ /* - xsns_48_chirp.ino - soil moisture sensor support for Sonoff-Tasmota +  xsns_48_chirp.ino - soil moisture sensor support for Sonoff-Tasmota - Copyright (C) 2019 Theo Arends & Christian Baars +  Copyright (C) 2019  Theo Arends & Christian Baars - 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 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. +  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 . +  You should have received a copy of the GNU General Public License +  along with this program.  If not, see . - -------------------------------------------------------------------------------------------- - Version Date Action Description - -------------------------------------------------------------------------------------------- +  -------------------------------------------------------------------------------------------- +  Version Date      Action    Description +  -------------------------------------------------------------------------------------------- - - --- - 1.0.0.0 20190608 started - further development by Christian Baars - https://github.com/Staars/Sonoff-Tasmota - forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota - base - code base from arendst and - https://github.com/Miceuz/i2c-moisture-sensor +  1.0.0.1 20190917  changed   - rework of the inner loop to enable delays in the middle of I2C-reads +                    added     - now really support for the (slower) CHIRP-Sensor +  --- +  1.0.0.0 20190608  started   - further development by Christian Baars  - https://github.com/Staars/Sonoff-Tasmota +                    forked    - from arendst/tasmota                    - https://github.com/arendst/Sonoff-Tasmota +                    base      - code base from arendst and              - https://github.com/Miceuz/i2c-moisture-sensor */ - -#ifdef USE_I2C -#ifdef USE_CHIRP +// #define USE_CHIRP +#ifdef USE_I2C +#ifdef USE_CHIRP /*********************************************************************************************\ - * CHIRP - Soil moisture sensor - * - * I2C Address: 0x20 - standard address, is changeable + * CHIRP - Soil moisture sensor + *  + * I2C Address: 0x20 - standard address, is changeable \*********************************************************************************************/ -#define XSNS_48 48 -#define CHIRP_MAX_SENSOR_COUNT 3 // 127 is expectectd to be the max number +#define XSNS_48                     48 +#define CHIRP_MAX_SENSOR_COUNT      3               // 127 is expectectd to be the max number -#define CHIRP_ADDR_STANDARD 0x20 // standard address +#define CHIRP_ADDR_STANDARD         0x20            // standard address /*********************************************************************************************\ - * constants + * constants \*********************************************************************************************/ -#define D_CMND_CHIRP "CHIRP" +#define D_CMND_CHIRP "CHIRP" -const char S_JSON_CHIRP_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}"; -const char S_JSON_CHIRP_COMMAND[] PROGMEM = "{\"" D_CMND_CHIRP "%s\"}"; -const char kCHIRP_Commands[] PROGMEM = "Select|Set|Scan|Reset|Sleep|Wake"; +const char S_JSON_CHIRP_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}"; +const char S_JSON_CHIRP_COMMAND[] PROGMEM        = "{\"" D_CMND_CHIRP "%s\"}"; +const char kCHIRP_Commands[] PROGMEM             = "Select|Set|Scan|Reset|Sleep|Wake"; -const char kChirpTypes[] PROGMEM = "CHIRP"; +const char kChirpTypes[] PROGMEM = "CHIRP"; /*********************************************************************************************\ - * enumerations + * enumerations \*********************************************************************************************/ -enum CHIRP_Commands { // commands useable in console or rules - CMND_CHIRP_SELECT, // select active sensor by I2C address, makes only sense for multiple sensors - CMND_CHIRP_SET, // set new I2C address for selected/active sensor, will reset - CMND_CHIRP_SCAN, // scan the I2C bus for one or more chirp sensors - CMND_CHIRP_RESET, // CHIRPReset, a fresh and default restart - CMND_CHIRP_SLEEP, // put sensor to sleep - CMND_CHIRP_WAKE }; // wake sensor by reading firmware version +enum CHIRP_Commands {                                 // commands useable in console or rules +  CMND_CHIRP_SELECT,                                  // select active sensor by I2C address, makes only sense for multiple sensors +  CMND_CHIRP_SET,                                     // set new I2C address for selected/active sensor, will reset +  CMND_CHIRP_SCAN,                                    // scan the I2C bus for one or more chirp sensors +  CMND_CHIRP_RESET,                                   // CHIRPReset, a fresh and default restart +  CMND_CHIRP_SLEEP,                                   // put sensor to sleep +  CMND_CHIRP_WAKE };                                  // wake sensor by reading firmware version /*********************************************************************************************\ - * command defines + * command defines \*********************************************************************************************/ -#define CHIRP_GET_CAPACITANCE 0x00 // 16 bit, read -#define CHIRP_SET_ADDRESS 0x01 // 8 bit, write -#define CHIRP_GET_ADDRESS 0x02 // 8 bit, read -#define CHIRP_MEASURE_LIGHT 0x03 // no value, write, -> initiate measurement, then wait at least 3 seconds -#define CHIRP_GET_LIGHT 0x04 // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated -#define CHIRP_GET_TEMPERATURE 0x05 // 16 bit, read -#define CHIRP_RESET 0x06 // no value, write -#define CHIRP_GET_VERSION 0x07 // 8 bit, read, -> 22 means 2.2 -#define CHIRP_SLEEP 0x08 // no value, write -#define CHIRP_GET_BUSY 0x09 // 8 bit, read, -> 1 = busy, 0 = otherwise +#define CHIRP_GET_CAPACITANCE       0x00            // 16 bit, read +#define CHIRP_SET_ADDRESS           0x01            // 8 bit,  write +#define CHIRP_GET_ADDRESS           0x02            // 8 bit,  read +#define CHIRP_MEASURE_LIGHT         0x03            // no value, write, -> initiate measurement, then wait at least 3 seconds +#define CHIRP_GET_LIGHT             0x04            // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated +#define CHIRP_GET_TEMPERATURE       0x05            // 16 bit, read +#define CHIRP_RESET                 0x06            // no value, write +#define CHIRP_GET_VERSION           0x07            // 8 bit, read, -> 22 means 2.2 +#define CHIRP_SLEEP                 0x08            // no value, write +#define CHIRP_GET_BUSY              0x09            // 8 bit, read, -> 1 = busy, 0 = otherwise /*********************************************************************************************\ - * helper function + * helper function \*********************************************************************************************/ -bool I2cWriteReg(uint8_t addr, uint8_t reg) -{ - return I2cWrite(addr, reg, 0, 0); +void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) { +  Wire.beginTransmission(addr); +  Wire.write(reg); +  Wire.endTransmission();  +} // now the original CHIRP needs 1100 ms delay + +uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) { +  Wire.requestFrom(addr,(uint8_t)2); +  uint16_t t = Wire.read() << 8; +  t = t | Wire.read(); +  return t; } /********************************************************************************************/ -// globals +// globals -uint8_t chirp_current = 0; // current selected/active sensor -uint8_t chirp_found_sensors = 0; // number of found sensors +uint8_t    chirp_current        = 0;    // current selected/active sensor +uint8_t    chirp_found_sensors  = 0;    // number of found sensors -char chirp_name[7]; -uint8_t chirp_next_job = 0; //0=reset, 1=auto-wake, 2=moisture+temperature, 3=light, 4 = pause; 5 = TELE done -uint32_t chirp_timeout_count = 0; //is handled every second, so value is equal to seconds (it is a slow sensor) +char       chirp_name[7]; +uint8_t    chirp_next_job       = 0;    //0=reset, 1=auto-wake, 2-9 = various measure steps; 10 = TELE done +uint32_t   chirp_timeout_count  = 0;    //is handled every second, so value is equal to seconds (it is a slow sensor) -#pragma pack(1) -struct ChirpSensor_t{ - uint16_t moisture = 0; // shall hold post-processed data, if implemented - uint16_t light = 0; // light level, maybe already postprocessed depending on the firmware - int16_t temperature= 0; // temperature in degrees CELSIUS * 10 - uint8_t version = 0; // firmware-version - uint8_t address:7; // we need only 7bit so... - uint8_t explicitSleep:1; // there is a free bit to play with ;) +#pragma pack(1) +struct ChirpSensor_t{ +    uint16_t   moisture = 0;      // shall hold post-processed data, if implemented +    uint16_t   light = 0;         // light level, maybe already postprocessed depending on the firmware +    int16_t    temperature= 0;    // temperature in degrees CELSIUS * 10 +    uint8_t    version = 0;       // firmware-version +    uint8_t    address:7;         // we need only 7bit so... +    uint8_t    explicitSleep:1;   // there is a free bit to play with ;) }; -#pragma pack() +#pragma pack() -ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT]; // should be 8 bytes per sensor slot +ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT];       // should be 8 bytes per sensor slot /********************************************************************************************/ -void ChirpReset(uint8_t addr) { - I2cWriteReg(addr, CHIRP_RESET); +void ChirpReset(uint8_t addr) { +    ChirpWriteI2CRegister(addr, CHIRP_RESET); } /********************************************************************************************/ -void ChirpResetAll(void) { - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version) { - ChirpReset(chirp_sensor[i].address); - } - } +void ChirpResetAll(void) { +    for (uint32_t i = 0; i < chirp_found_sensors; i++) { +      if (chirp_sensor[i].version) {  +        ChirpReset(chirp_sensor[i].address); +        } +    } } /********************************************************************************************/ -void ChirpClockSet() { // set I2C for this slow sensor - Wire.setClockStretchLimit(4000); - Wire.setClock(50000); +void ChirpClockSet() { // set I2C for this slow sensor +    Wire.setClockStretchLimit(4000); +    Wire.setClock(50000); } /********************************************************************************************/ -void ChirpSleep(uint8_t addr) { - I2cWriteReg(addr, CHIRP_SLEEP); +void ChirpSleep(uint8_t addr) { +    ChirpWriteI2CRegister(addr, CHIRP_SLEEP); } /********************************************************************************************/ -// void ChirpSleepAll(void) { -// for (uint32_t i = 0; i < chirp_found_sensors; i++) { -// if (chirp_sensor[i].version) { -// ChirpSleep(chirp_sensor[i].address); -// } -// } -// } +// void ChirpSleepAll(void) { +//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { +//       if (chirp_sensor[i].version) {  +//         ChirpSleep(chirp_sensor[i].address); +//         } +//     } +// } -// /********************************************************************************************/ +// /********************************************************************************************/ -// void ChirpAutoWakeAll(void) { -// for (uint32_t i = 0; i < chirp_found_sensors; i++) { -// if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { -// ChirpReadVersion(chirp_sensor[i].address); -// } -// } -// } +// void ChirpAutoWakeAll(void) { +//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { +//       if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  +//         ChirpReadVersion(chirp_sensor[i].address); +//         } +//     } +// } /********************************************************************************************/ -void ChirpSelect(uint8_t sensor) { - if(sensor < chirp_found_sensors) { //TODO: show some infos - chirp_current = sensor; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: Sensor %u now active."), chirp_current); - } - if (sensor == 255) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); - } +void ChirpSelect(uint8_t sensor) { +  if(sensor < chirp_found_sensors) { //TODO: show some infos +    chirp_current = sensor; +    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current); +  } +  if (sensor == 255) { +    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); +  } } /********************************************************************************************/ -bool ChirpMeasureLight(void) { - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { - uint8_t lightReady = I2cRead8(chirp_sensor[i].address, CHIRP_GET_BUSY); - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: busy status for light for sensor %u"), lightReady); - if (lightReady == 1) { - return false; // a measurement is still in progress, we stop everything and come back in the next loop = 1 second - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: init measure light for sensor %u"), i); - I2cWriteReg(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); - } - } - return true; // we could read all values (maybe at different times, but that does not really matter) and consider this job finished +// bool ChirpMeasureLight(void) { +//   for (uint32_t i = 0; i < chirp_found_sensors; i++) { +//     if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  +//       uint8_t lightReady = I2cRead8(chirp_sensor[i].address, CHIRP_GET_BUSY); +//       DEBUG_SENSOR_LOG(PSTR("CHIRP: busy status for light for sensor %u"), lightReady); +//       if (lightReady == 1) { +//         return false; // a measurement is still in progress, we stop everything and come back in the next loop = 1 second +//       } +//       DEBUG_SENSOR_LOG(PSTR("CHIRP: init measure light for sensor %u"), i); +//       ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT);  +//       } +//   } +//   return true; // we could read all values (maybe at different times, but that does not really matter) and consider this job finished +// } + +/********************************************************************************************/ + +// void ChirpReadCapTemp() { // no timeout needed for both measurements, so we do it at once +//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { +//       if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  +//         DEBUG_SENSOR_LOG(PSTR("CHIRP: now really read CapTemp for sensor at address 0x%x"), chirp_sensor[i].address); +//         chirp_sensor[i].moisture = I2cRead16(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); +//         chirp_sensor[i].temperature = I2cRead16(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE);  +//         } +//     } +// } + +/********************************************************************************************/ + +// bool ChirpReadLight() {   // sophisticated calculations could be done here +//   bool success = false; +//   for (uint32_t i = 0; i < chirp_found_sensors; i++) { +//     DEBUG_SENSOR_LOG(PSTR("CHIRP: will read light for sensor %u"), i); +//     if (chirp_sensor[i].version) { +//       if (I2cValidRead16(&chirp_sensor[i].light, chirp_sensor[i].address, CHIRP_GET_LIGHT)){ +//         DEBUG_SENSOR_LOG(PSTR("CHIRP: light read success")); +//         success = true; +//       } +//       if(!chirp_sensor[i].explicitSleep){ success = true;}  +//       } +//   } +//   return success; +// } + +/********************************************************************************************/ + +uint8_t ChirpReadVersion(uint8_t addr) { +  return (I2cRead8(addr, CHIRP_GET_VERSION)); } /********************************************************************************************/ -void ChirpReadCapTemp() { // no timeout needed for both measurements, so we do it at once - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: now really read CapTemp for sensor at address 0x%x"), chirp_sensor[i].address); - chirp_sensor[i].moisture = I2cRead16(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); - chirp_sensor[i].temperature = I2cRead16(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); - } - } +bool ChirpSet(uint8_t addr) { +  if(addr < 128){ +    if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ +      I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); // two calls are needed for sensor firmware version 2.6 +      DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr); +      ChirpReset(chirp_sensor[chirp_current].address); +      chirp_sensor[chirp_current].address = addr; +      return true; +    } +  } +  return false; } /********************************************************************************************/ -bool ChirpReadLight() { // sophisticated calculations could be done here - bool success = false; - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: will read light for sensor %u"), i); - if (chirp_sensor[i].version) { - if (I2cValidRead16(&chirp_sensor[i].light, chirp_sensor[i].address, CHIRP_GET_LIGHT)){ - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: light read success")); - success = true; - } - if(!chirp_sensor[i].explicitSleep){ success = true;} - } - } - return success; +bool ChirpScan() { +    ChirpClockSet(); +    chirp_found_sensors = 0; +    for (uint8_t address = 1; address <= 127; address++) { +      chirp_sensor[chirp_found_sensors].version = 0; +      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); +      delay(2); +      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); +      if(chirp_sensor[chirp_found_sensors].version > 0) { +        AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address);     +        if(chirp_found_sensors 0) { - AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address); - if(chirp_found_sensors 0) { - return; - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: scan will start ...")); - if (ChirpScan()) { - uint8_t chirp_model = 0; // TODO: ?? - GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); - } +  if (chirp_next_job > 0) { +    return; +  } +  DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ...")); +  if (ChirpScan()) { +    uint8_t chirp_model = 0;  // TODO: ?? +    GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); +  } } - - /********************************************************************************************/ -void ChirpEverySecond(void) -{ - // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: every second")); - if(chirp_timeout_count == 0) { //countdown complete, now do something - switch(chirp_next_job) { - case 0: //this should only be called after driver initialization - AddLog_P2(LOG_LEVEL_DEBUG,PSTR( "CHIRP: reset all")); - ChirpResetAll(); - chirp_timeout_count = 1; - chirp_next_job++; - break; - case 1: // auto-sleep-wake seems to expose a fundamental I2C-problem of the sensor and is deactivated - // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: auto-wake all")); - // ChirpAutoWakeAll(); // this is only a wake-up call at the start of next read cycle - chirp_next_job++; // go on, next job should start in a second - break; - case 2: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: call CapTemp twice")); - ChirpReadCapTemp(); // it is reported to be useful, to read twice, because otherwise old values are received - ChirpReadCapTemp(); // this is the "real" read call, we simply overwrite the existing values - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: call measure light")); - ChirpMeasureLight(); // prepare the next step -> initiate light read - chirp_timeout_count = 2; // wait 3 seconds, no need to hurry ... - chirp_next_job++; - break; - case 3: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: call read light")); - if (ChirpReadLight()){ // now read light and if successful continue, otherwise come back in a second and try again - // AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: auto-sleep all")); - // ChirpSleepAll(); // let all sensors auto-sleep - chirp_next_job++; - } - break; - case 4: - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: paused, waiting for TELE")); - break; - case 5: - if (Settings.tele_period > 9){ - chirp_timeout_count = Settings.tele_period - 10; // sync it with the TELEPERIOD, we need about up to 10 seconds to measure, depending on the light level - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: timeout: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); - } - chirp_next_job = 1; // back to step 1 - break; - } - } - else { - chirp_timeout_count--; // count down - } +void ChirpServiceAllSensors(uint8_t job){ +  for (uint32_t i = 0; i < chirp_found_sensors; i++) { +    if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  +      DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare for sensor at address 0x%x"), chirp_sensor[i].address); +      switch(job){ +        case 0: +        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); +        break; +        case 1: +        chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); +        break; +        case 2: +        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); +        break; +        case 3: +        chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); +        break; +        case 4: +        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); +        break; +        case 5: +        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT); +        break; +        case 6: +        chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); +        break; +        default: +        break; +      } +    } +  }   } /********************************************************************************************/ -// normaly in i18n.h -#define D_JSON_MOISTURE "Moisture" +void ChirpEvery100MSecond(void) +{ +  // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); +  if(chirp_timeout_count == 0) {    //countdown complete, now do something +      switch(chirp_next_job) { +          case 0:                   //this should only be called after driver initialization +          DEBUG_SENSOR_LOG(PSTR( "CHIRP: reset all")); +          ChirpResetAll(); +          chirp_timeout_count = 10; // wait a second +          chirp_next_job++; +          break; +          case 1:                   // auto-sleep-wake seems to expose a fundamental I2C-problem of the sensor and is deactivated +          // DEBUG_SENSOR_LOG(PSTR("CHIRP: auto-wake all")); +          // ChirpAutoWakeAll();       // this is only a wake-up call at the start of next read cycle +          chirp_next_job++;         // go on, next job should start in a second +          break; +          case 2: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read")); +          ChirpServiceAllSensors(0);   +          chirp_timeout_count = 11;  // wait 1.1 seconds,  +          chirp_next_job++; +          break; +          case 3: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read")); +          ChirpServiceAllSensors(1);  +          chirp_next_job++; +          break; +          case 4: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd")); +          ChirpServiceAllSensors(0);  +          chirp_timeout_count = 11;  // wait 1.1 seconds,  +          chirp_next_job++; +          break; +          case 5: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd")); +          ChirpServiceAllSensors(1);  +          chirp_next_job++; +          break; +          case 6: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read")); +          ChirpServiceAllSensors(2);  +          chirp_timeout_count = 11;  // wait 1.1 seconds,  +          chirp_next_job++; +          break; +          case 7: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read")); +          ChirpServiceAllSensors(3);  +          chirp_next_job++; +          break; +          case 8: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd")); +          ChirpServiceAllSensors(2); +          chirp_timeout_count = 11;  // wait 1.1 seconds,  +          chirp_next_job++; +          break; +          case 9: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd")); +          ChirpServiceAllSensors(3); +          chirp_next_job++; +          break;        +          case 10: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process")); +          ChirpServiceAllSensors(4); +          chirp_timeout_count = 90;  // wait 9 seconds,   +          chirp_next_job++; +          break; +          case 11: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read")); +          ChirpServiceAllSensors(5); +          chirp_timeout_count = 11;  // wait 1.1 seconds,  +          chirp_next_job++; +          break; +          case 12: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read")); +          ChirpServiceAllSensors(6); +          chirp_next_job++; +          break;      +          case 13: +          DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); +          break; +          case 14: +          if (Settings.tele_period > 16){ +              chirp_timeout_count = (Settings.tele_period - 17) * 10;  // sync it with the TELEPERIOD, we need about up to 17 seconds to measure +              DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); +            } +          else{ +            AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); +          } +          chirp_next_job = 1;                                 // back to step 1 +          break; +      } +  } +  else { +      chirp_timeout_count--;         // count down +  } +} -#ifdef USE_WEBSERVER - // {s} = , {m} = , {e} = +/********************************************************************************************/ +// normaly in i18n.h - const char HTTP_SNS_MOISTURE[] PROGMEM = "{s} " D_JSON_MOISTURE ": {m}%s %{e}"; - const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address: {m}0x%x{e}" - "{s} FW-version: {m}%s {e}"; ; - const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; -#endif // USE_WEBSERVER +#define D_JSON_MOISTURE "Moisture" + +#ifdef USE_WEBSERVER +  // {s} = , {m} = , {e} =  + + const char HTTP_SNS_MOISTURE[] PROGMEM = "{s} " D_JSON_MOISTURE ": {m}%s %{e}"; + const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address: {m}0x%x{e}" +                                          "{s} FW-version: {m}%s {e}";                                                                                            ; + const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; +#endif  // USE_WEBSERVER /********************************************************************************************/ -void ChirpShow(bool json) +void ChirpShow(bool json) { - for (uint32_t i = 0; i < chirp_found_sensors; i++) { - if (chirp_sensor[i].version) { - // convert double values to string - char str_moisture[33]; - dtostrfd(chirp_sensor[i].moisture, 0, str_moisture); - char str_temperature[33]; - double t_temperature = ((double) chirp_sensor[i].temperature )/10.0; - dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); - char str_light[33]; - dtostrfd(chirp_sensor[i].light, 0, str_light); - char str_version[33]; - dtostrfd(chirp_sensor[i].version, 0, str_version); - if (json) { - if(!chirp_sensor[i].explicitSleep){ - ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":\"%s}"), - chirp_name, i, str_moisture, str_temperature, str_light);} - else { - ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"), - chirp_name, i); - } - #ifdef USE_DOMOTICZ - if (0 == tele_period) { - DomoticzTempHumSensor(str_temperature, str_moisture); - DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); - } - #endif // USE_DOMOTICZ - #ifdef USE_WEBSERVER - } else { - WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); - if (chirp_sensor[i].explicitSleep){ - WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); - } - else { - WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture); - WSContentSend_PD(HTTP_SNS_ILLUMINANCE, " ", chirp_sensor[i].light); - WSContentSend_PD(HTTP_SNS_TEMP, " ",str_temperature, TempUnit()); - } - - #endif // USE_WEBSERVER - } - } - } +  for (uint32_t i = 0; i < chirp_found_sensors; i++) { +    if (chirp_sensor[i].version) { +      // convert double values to string +      char str_moisture[33];       +      dtostrfd(chirp_sensor[i].moisture, 0, str_moisture); +      char str_temperature[33]; +      double t_temperature = ((double) chirp_sensor[i].temperature )/10.0;    +      dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); +      char str_light[33];       +      dtostrfd(chirp_sensor[i].light, 0, str_light); +      char str_version[33];       +      dtostrfd(chirp_sensor[i].version, 0, str_version); +      if (json) { +        if(!chirp_sensor[i].explicitSleep){ +          ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":\"%s}"), +          chirp_name, i, str_moisture, str_temperature, str_light);} +        else { +          ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"), +          chirp_name, i); +        } +  #ifdef USE_DOMOTICZ +      if (0 == tele_period) { +              DomoticzTempHumSensor(str_temperature, str_moisture); +              DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); +        } +  #endif  // USE_DOMOTICZ +  #ifdef USE_WEBSERVER +      } else { +        WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); +        if (chirp_sensor[i].explicitSleep){ +          WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); +        } +        else { +          WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture); +          WSContentSend_PD(HTTP_SNS_ILLUMINANCE, " ", chirp_sensor[i].light); +          WSContentSend_PD(HTTP_SNS_TEMP, " ",str_temperature, TempUnit());    +        } +   +  #endif  // USE_WEBSERVER +      } +    } +  }   } /*********************************************************************************************\ - * check the Chirp commands + * check the Chirp commands \*********************************************************************************************/ -bool ChirpCmd(void) { - char command[CMDSZ]; - bool serviced = true; - uint8_t disp_len = strlen(D_CMND_CHIRP); +bool ChirpCmd(void) { +  char command[CMDSZ]; +  bool serviced = true; +  uint8_t disp_len = strlen(D_CMND_CHIRP); - if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) { // prefix - int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands); +  if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) {  // prefix +    int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands); - switch (command_code) { - case CMND_CHIRP_SELECT: - case CMND_CHIRP_SET: - if (XdrvMailbox.data_len > 0) { - if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(XdrvMailbox.payload); } //select active sensor, i.e. for wake, sleep or reset - if (command_code == CMND_CHIRP_SET) { ChirpSet((uint8_t)XdrvMailbox.payload); } //set and change I2C-address of selected sensor - Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload); - } - else { - if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(255); } //show active sensor - Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); - } - break; - case CMND_CHIRP_SCAN: - case CMND_CHIRP_SLEEP: - case CMND_CHIRP_WAKE: - case CMND_CHIRP_RESET: - if (command_code == CMND_CHIRP_SCAN) { chirp_next_job = 0; - ChirpDetect(); } // this will re-init the sensor array - if (command_code == CMND_CHIRP_SLEEP) { chirp_sensor[chirp_current].explicitSleep = true; // we do not touch this sensor in the read functions - ChirpSleep(chirp_sensor[chirp_current].address); } - if (command_code == CMND_CHIRP_WAKE) { chirp_sensor[chirp_current].explicitSleep = false; // back in action - ChirpReadVersion(chirp_sensor[chirp_current].address); } // just use read version as wakeup call - if (command_code == CMND_CHIRP_RESET) { ChirpReset(chirp_sensor[chirp_current].address); } - Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); - break; - default: - // else for Unknown command - serviced = false; - break; - } - } - return serviced; +    switch (command_code) { +      case CMND_CHIRP_SELECT: +      case CMND_CHIRP_SET: +        if (XdrvMailbox.data_len > 0) { +          if (command_code == CMND_CHIRP_SELECT)  { ChirpSelect(XdrvMailbox.payload); }                       //select active sensor, i.e. for wake, sleep or reset +          if (command_code == CMND_CHIRP_SET)     { ChirpSet((uint8_t)XdrvMailbox.payload); }                 //set and change I2C-address of selected sensor +        Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload); +        } +        else { +          if (command_code == CMND_CHIRP_SELECT)  { ChirpSelect(255); }                                       //show active sensor +        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); +        }      +        break; +      case CMND_CHIRP_SCAN:  +      case CMND_CHIRP_SLEEP: +      case CMND_CHIRP_WAKE: +      case CMND_CHIRP_RESET: +        if (command_code == CMND_CHIRP_SCAN)     {  chirp_next_job = 0; +                                                    ChirpDetect(); }                                            // this will re-init the sensor array +        if (command_code == CMND_CHIRP_SLEEP)    {  chirp_sensor[chirp_current].explicitSleep = true;         // we do not touch this sensor in the read functions +                                                    ChirpSleep(chirp_sensor[chirp_current].address); } +        if (command_code == CMND_CHIRP_WAKE)     {  chirp_sensor[chirp_current].explicitSleep = false;        // back in action +                                                    ChirpReadVersion(chirp_sensor[chirp_current].address); }  // just use read version as wakeup call                                          +        if (command_code == CMND_CHIRP_RESET)    { ChirpReset(chirp_sensor[chirp_current].address); } +        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); +        break; +      default: +        // else for Unknown command +        serviced = false; +      break; +    } +  } +  return serviced; } /*********************************************************************************************\ - * Interface + * Interface \*********************************************************************************************/ -bool Xsns48(uint8_t function) +bool Xsns48(uint8_t function) { - bool result = false; +  bool result = false; - if (i2c_flg) { - switch (function) { - case FUNC_INIT: - ChirpDetect(); // We can call CHIRPSCAN later to re-detect - break; - case FUNC_EVERY_SECOND: - if(chirp_found_sensors > 0){ - ChirpEverySecond(); - } - break; - case FUNC_COMMAND: - result = ChirpCmd(); - break; - case FUNC_JSON_APPEND: - ChirpShow(1); - chirp_next_job = 5; // TELE done, now compute time for next measure cycle - break; -#ifdef USE_WEBSERVER - case FUNC_WEB_SENSOR: - ChirpShow(0); - break; -#endif // USE_WEBSERVER - } - } - return result; +  if (i2c_flg) {   +    switch (function) { +      case FUNC_INIT: +        ChirpDetect();         // We can call CHIRPSCAN later to re-detect +        break; +      case FUNC_EVERY_100_MSECOND: +        if(chirp_found_sensors > 0){ +          ChirpEvery100MSecond(); +        }     +        break; +      case FUNC_COMMAND: +        result = ChirpCmd();   +        break; +      case FUNC_JSON_APPEND: +        ChirpShow(1); +        chirp_next_job = 14; // TELE done, now compute time for next measure cycle +        break; +#ifdef USE_WEBSERVER +      case FUNC_WEB_SENSOR: +        ChirpShow(0); +        break; +#endif  // USE_WEBSERVER +    } +  } +  return result; } -#endif // USE_CHIRP -#endif // USE_I2C \ No newline at end of file +#endif  // USE_CHIRP +#endif  // USE_I2C From eb8539dd9198092064c4e05a82d35d57f177a163 Mon Sep 17 00:00:00 2001 From: Staars Date: Wed, 18 Sep 2019 20:57:35 +0200 Subject: [PATCH 2/6] name it DARKNESS, handle non-reading of temperature, small bugfixes --- sonoff/xsns_48_chirp.ino | 870 +++++++++++++++++++-------------------- 1 file changed, 417 insertions(+), 453 deletions(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index c54c10878..53a5e3768 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -1,571 +1,535 @@ /* -  xsns_48_chirp.ino - soil moisture sensor support for Sonoff-Tasmota + xsns_48_chirp.ino - soil moisture sensor support for Sonoff-Tasmota -  Copyright (C) 2019  Theo Arends & Christian Baars + Copyright (C) 2019 Theo Arends & Christian Baars -  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 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. + 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 . + You should have received a copy of the GNU General Public License + along with this program. If not, see . -  -------------------------------------------------------------------------------------------- -  Version Date      Action    Description -  -------------------------------------------------------------------------------------------- + -------------------------------------------------------------------------------------------- + Version Date Action Description + -------------------------------------------------------------------------------------------- -  1.0.0.1 20190917  changed   - rework of the inner loop to enable delays in the middle of I2C-reads -                    added     - now really support for the (slower) CHIRP-Sensor -  --- -  1.0.0.0 20190608  started   - further development by Christian Baars  - https://github.com/Staars/Sonoff-Tasmota -                    forked    - from arendst/tasmota                    - https://github.com/arendst/Sonoff-Tasmota -                    base      - code base from arendst and              - https://github.com/Miceuz/i2c-moisture-sensor + 1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads + changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS + changed - do not publish missing temperature reads + added - now really support for the (slower) CHIRP-Sensor + --- + 1.0.0.0 20190608 started - further development by Christian Baars - https://github.com/Staars/Sonoff-Tasmota + forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota + base - code base from arendst and - https://github.com/Miceuz/i2c-moisture-sensor */ -// #define USE_CHIRP -#ifdef USE_I2C -#ifdef USE_CHIRP + +#define USE_CHIRP +#ifdef USE_I2C +#ifdef USE_CHIRP /*********************************************************************************************\ - * CHIRP - Soil moisture sensor - *  - * I2C Address: 0x20 - standard address, is changeable + * CHIRP - Soil moisture sensor + * + * I2C Address: 0x20 - standard address, is changeable \*********************************************************************************************/ -#define XSNS_48                     48 -#define CHIRP_MAX_SENSOR_COUNT      3               // 127 is expectectd to be the max number +#define XSNS_48 48 +#define CHIRP_MAX_SENSOR_COUNT 3 // 127 is expectectd to be the max number -#define CHIRP_ADDR_STANDARD         0x20            // standard address +#define CHIRP_ADDR_STANDARD 0x20 // standard address /*********************************************************************************************\ - * constants + * constants \*********************************************************************************************/ -#define D_CMND_CHIRP "CHIRP" +#define D_CMND_CHIRP "CHIRP" -const char S_JSON_CHIRP_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}"; -const char S_JSON_CHIRP_COMMAND[] PROGMEM        = "{\"" D_CMND_CHIRP "%s\"}"; -const char kCHIRP_Commands[] PROGMEM             = "Select|Set|Scan|Reset|Sleep|Wake"; +const char S_JSON_CHIRP_COMMAND_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}"; +const char S_JSON_CHIRP_COMMAND[] PROGMEM = "{\"" D_CMND_CHIRP "%s\"}"; +const char kCHIRP_Commands[] PROGMEM = "Select|Set|Scan|Reset|Sleep|Wake"; -const char kChirpTypes[] PROGMEM = "CHIRP"; +const char kChirpTypes[] PROGMEM = "CHIRP"; /*********************************************************************************************\ - * enumerations + * enumerations \*********************************************************************************************/ -enum CHIRP_Commands {                                 // commands useable in console or rules -  CMND_CHIRP_SELECT,                                  // select active sensor by I2C address, makes only sense for multiple sensors -  CMND_CHIRP_SET,                                     // set new I2C address for selected/active sensor, will reset -  CMND_CHIRP_SCAN,                                    // scan the I2C bus for one or more chirp sensors -  CMND_CHIRP_RESET,                                   // CHIRPReset, a fresh and default restart -  CMND_CHIRP_SLEEP,                                   // put sensor to sleep -  CMND_CHIRP_WAKE };                                  // wake sensor by reading firmware version +enum CHIRP_Commands { // commands useable in console or rules + CMND_CHIRP_SELECT, // select active sensor by I2C address, makes only sense for multiple sensors + CMND_CHIRP_SET, // set new I2C address for selected/active sensor, will reset + CMND_CHIRP_SCAN, // scan the I2C bus for one or more chirp sensors + CMND_CHIRP_RESET, // CHIRPReset, a fresh and default restart + CMND_CHIRP_SLEEP, // put sensor to sleep + CMND_CHIRP_WAKE }; // wake sensor by reading firmware version /*********************************************************************************************\ - * command defines + * command defines \*********************************************************************************************/ -#define CHIRP_GET_CAPACITANCE       0x00            // 16 bit, read -#define CHIRP_SET_ADDRESS           0x01            // 8 bit,  write -#define CHIRP_GET_ADDRESS           0x02            // 8 bit,  read -#define CHIRP_MEASURE_LIGHT         0x03            // no value, write, -> initiate measurement, then wait at least 3 seconds -#define CHIRP_GET_LIGHT             0x04            // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated -#define CHIRP_GET_TEMPERATURE       0x05            // 16 bit, read -#define CHIRP_RESET                 0x06            // no value, write -#define CHIRP_GET_VERSION           0x07            // 8 bit, read, -> 22 means 2.2 -#define CHIRP_SLEEP                 0x08            // no value, write -#define CHIRP_GET_BUSY              0x09            // 8 bit, read, -> 1 = busy, 0 = otherwise +#define CHIRP_GET_CAPACITANCE 0x00 // 16 bit, read +#define CHIRP_SET_ADDRESS 0x01 // 8 bit, write +#define CHIRP_GET_ADDRESS 0x02 // 8 bit, read +#define CHIRP_MEASURE_LIGHT 0x03 // no value, write, -> initiate measurement, then wait at least 3 seconds +#define CHIRP_GET_LIGHT 0x04 // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated +#define CHIRP_GET_TEMPERATURE 0x05 // 16 bit, read +#define CHIRP_RESET 0x06 // no value, write +#define CHIRP_GET_VERSION 0x07 // 8 bit, read, -> 22 means 2.2 +#define CHIRP_SLEEP 0x08 // no value, write +#define CHIRP_GET_BUSY 0x09 // 8 bit, read, -> 1 = busy, 0 = otherwise /*********************************************************************************************\ - * helper function + * helper function \*********************************************************************************************/ -void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) { -  Wire.beginTransmission(addr); -  Wire.write(reg); -  Wire.endTransmission();  -} // now the original CHIRP needs 1100 ms delay +void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) { + Wire.beginTransmission(addr); + Wire.write(reg); + Wire.endTransmission(); +} // now the original CHIRP needs 1100 ms delay -uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) { -  Wire.requestFrom(addr,(uint8_t)2); -  uint16_t t = Wire.read() << 8; -  t = t | Wire.read(); -  return t; +uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) { + Wire.requestFrom(addr,(uint8_t)2); + uint16_t t = Wire.read() << 8; + t = t | Wire.read(); + return t; } /********************************************************************************************/ -// globals +// globals -uint8_t    chirp_current        = 0;    // current selected/active sensor -uint8_t    chirp_found_sensors  = 0;    // number of found sensors +uint8_t chirp_current = 0; // current selected/active sensor +uint8_t chirp_found_sensors = 0; // number of found sensors -char       chirp_name[7]; -uint8_t    chirp_next_job       = 0;    //0=reset, 1=auto-wake, 2-9 = various measure steps; 10 = TELE done -uint32_t   chirp_timeout_count  = 0;    //is handled every second, so value is equal to seconds (it is a slow sensor) +char chirp_name[7]; +uint8_t chirp_next_job = 0; //0=reset, 1=auto-wake, 2-13 = various measure steps; 14 = TELE done +uint32_t chirp_timeout_count = 0; //is handled every second, so value is equal to seconds (it is a slow sensor) -#pragma pack(1) -struct ChirpSensor_t{ -    uint16_t   moisture = 0;      // shall hold post-processed data, if implemented -    uint16_t   light = 0;         // light level, maybe already postprocessed depending on the firmware -    int16_t    temperature= 0;    // temperature in degrees CELSIUS * 10 -    uint8_t    version = 0;       // firmware-version -    uint8_t    address:7;         // we need only 7bit so... -    uint8_t    explicitSleep:1;   // there is a free bit to play with ;) +#pragma pack(1) +struct ChirpSensor_t{ + uint16_t moisture = 0; // shall hold post-processed data, if implemented + uint16_t light = 0; // light level, maybe already postprocessed depending on the firmware + int16_t temperature = 0; // temperature in degrees CELSIUS * 10 , we will also store the I2C error code + uint8_t version = 0; // firmware-version + uint8_t address:7; // we need only 7bit so... + uint8_t explicitSleep:1; // there is a free bit to play with ;) }; -#pragma pack() +#pragma pack() -ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT];       // should be 8 bytes per sensor slot +ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT]; // should be 8 bytes per sensor slot /********************************************************************************************/ -void ChirpReset(uint8_t addr) { -    ChirpWriteI2CRegister(addr, CHIRP_RESET); +void ChirpReset(uint8_t addr) { + ChirpWriteI2CRegister(addr, CHIRP_RESET); } /********************************************************************************************/ -void ChirpResetAll(void) { -    for (uint32_t i = 0; i < chirp_found_sensors; i++) { -      if (chirp_sensor[i].version) {  -        ChirpReset(chirp_sensor[i].address); -        } -    } +void ChirpResetAll(void) { + for (uint32_t i = 0; i < chirp_found_sensors; i++) { + if (chirp_sensor[i].version) { + ChirpReset(chirp_sensor[i].address); + } + } } /********************************************************************************************/ -void ChirpClockSet() { // set I2C for this slow sensor -    Wire.setClockStretchLimit(4000); -    Wire.setClock(50000); +void ChirpClockSet() { // set I2C for this slow sensor + Wire.setClockStretchLimit(4000); + Wire.setClock(50000); } /********************************************************************************************/ -void ChirpSleep(uint8_t addr) { -    ChirpWriteI2CRegister(addr, CHIRP_SLEEP); +void ChirpSleep(uint8_t addr) { + ChirpWriteI2CRegister(addr, CHIRP_SLEEP); } /********************************************************************************************/ -// void ChirpSleepAll(void) { -//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { -//       if (chirp_sensor[i].version) {  -//         ChirpSleep(chirp_sensor[i].address); -//         } -//     } -// } +// void ChirpSleepAll(void) { +// for (uint32_t i = 0; i < chirp_found_sensors; i++) { +// if (chirp_sensor[i].version) { +// ChirpSleep(chirp_sensor[i].address); +// } +// } +// } -// /********************************************************************************************/ +// /********************************************************************************************/ -// void ChirpAutoWakeAll(void) { -//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { -//       if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  -//         ChirpReadVersion(chirp_sensor[i].address); -//         } -//     } -// } +// void ChirpAutoWakeAll(void) { +// for (uint32_t i = 0; i < chirp_found_sensors; i++) { +// if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { +// ChirpReadVersion(chirp_sensor[i].address); +// } +// } +// } /********************************************************************************************/ -void ChirpSelect(uint8_t sensor) { -  if(sensor < chirp_found_sensors) { //TODO: show some infos -    chirp_current = sensor; -    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current); -  } -  if (sensor == 255) { -    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); -  } +void ChirpSelect(uint8_t sensor) { + if(sensor < chirp_found_sensors) { //TODO: show some infos + chirp_current = sensor; + DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current); + } + if (sensor == 255) { + DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); + } } /********************************************************************************************/ -// bool ChirpMeasureLight(void) { -//   for (uint32_t i = 0; i < chirp_found_sensors; i++) { -//     if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  -//       uint8_t lightReady = I2cRead8(chirp_sensor[i].address, CHIRP_GET_BUSY); -//       DEBUG_SENSOR_LOG(PSTR("CHIRP: busy status for light for sensor %u"), lightReady); -//       if (lightReady == 1) { -//         return false; // a measurement is still in progress, we stop everything and come back in the next loop = 1 second -//       } -//       DEBUG_SENSOR_LOG(PSTR("CHIRP: init measure light for sensor %u"), i); -//       ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT);  -//       } -//   } -//   return true; // we could read all values (maybe at different times, but that does not really matter) and consider this job finished -// } - -/********************************************************************************************/ - -// void ChirpReadCapTemp() { // no timeout needed for both measurements, so we do it at once -//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { -//       if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  -//         DEBUG_SENSOR_LOG(PSTR("CHIRP: now really read CapTemp for sensor at address 0x%x"), chirp_sensor[i].address); -//         chirp_sensor[i].moisture = I2cRead16(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); -//         chirp_sensor[i].temperature = I2cRead16(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE);  -//         } -//     } -// } - -/********************************************************************************************/ - -// bool ChirpReadLight() {   // sophisticated calculations could be done here -//   bool success = false; -//   for (uint32_t i = 0; i < chirp_found_sensors; i++) { -//     DEBUG_SENSOR_LOG(PSTR("CHIRP: will read light for sensor %u"), i); -//     if (chirp_sensor[i].version) { -//       if (I2cValidRead16(&chirp_sensor[i].light, chirp_sensor[i].address, CHIRP_GET_LIGHT)){ -//         DEBUG_SENSOR_LOG(PSTR("CHIRP: light read success")); -//         success = true; -//       } -//       if(!chirp_sensor[i].explicitSleep){ success = true;}  -//       } -//   } -//   return success; -// } - -/********************************************************************************************/ - -uint8_t ChirpReadVersion(uint8_t addr) { -  return (I2cRead8(addr, CHIRP_GET_VERSION)); +uint8_t ChirpReadVersion(uint8_t addr) { + return (I2cRead8(addr, CHIRP_GET_VERSION)); } /********************************************************************************************/ -bool ChirpSet(uint8_t addr) { -  if(addr < 128){ -    if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ -      I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); // two calls are needed for sensor firmware version 2.6 -      DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr); -      ChirpReset(chirp_sensor[chirp_current].address); -      chirp_sensor[chirp_current].address = addr; -      return true; -    } -  } -  return false; +bool ChirpSet(uint8_t addr) { + if(addr < 128){ + if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ + I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); // two calls are needed for sensor firmware version 2.6 + DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr); + ChirpReset(chirp_sensor[chirp_current].address); + chirp_sensor[chirp_current].address = addr; + return true; + } + } + return false; } /********************************************************************************************/ -bool ChirpScan() { -    ChirpClockSet(); -    chirp_found_sensors = 0; -    for (uint8_t address = 1; address <= 127; address++) { -      chirp_sensor[chirp_found_sensors].version = 0; -      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); -      delay(2); -      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); -      if(chirp_sensor[chirp_found_sensors].version > 0) { -        AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address);     -        if(chirp_found_sensors 0) { + AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address); + if(chirp_found_sensors 0) { -    return; -  } -  DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ...")); -  if (ChirpScan()) { -    uint8_t chirp_model = 0;  // TODO: ?? -    GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); -  } + if (chirp_next_job > 0) { + return; + } + DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ...")); + if (ChirpScan()) { + uint8_t chirp_model = 0; // TODO: ?? + GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); + } } /********************************************************************************************/ -void ChirpServiceAllSensors(uint8_t job){ -  for (uint32_t i = 0; i < chirp_found_sensors; i++) { -    if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  -      DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare for sensor at address 0x%x"), chirp_sensor[i].address); -      switch(job){ -        case 0: -        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); -        break; -        case 1: -        chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); -        break; -        case 2: -        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); -        break; -        case 3: -        chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); -        break; -        case 4: -        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); -        break; -        case 5: -        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT); -        break; -        case 6: -        chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); -        break; -        default: -        break; -      } -    } -  }   +void ChirpServiceAllSensors(uint8_t job){ + for (uint32_t i = 0; i < chirp_found_sensors; i++) { + if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) { + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare for sensor at address 0x%x"), chirp_sensor[i].address); + switch(job){ + case 0: + ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); + break; + case 1: + chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); + break; + case 2: + ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); + break; + case 3: + chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); + break; + case 4: + ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); + break; + case 5: + ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT); + break; + case 6: + chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); + break; + default: + break; + } + } + } } /********************************************************************************************/ -void ChirpEvery100MSecond(void) +void ChirpEvery100MSecond(void) { -  // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); -  if(chirp_timeout_count == 0) {    //countdown complete, now do something -      switch(chirp_next_job) { -          case 0:                   //this should only be called after driver initialization -          DEBUG_SENSOR_LOG(PSTR( "CHIRP: reset all")); -          ChirpResetAll(); -          chirp_timeout_count = 10; // wait a second -          chirp_next_job++; -          break; -          case 1:                   // auto-sleep-wake seems to expose a fundamental I2C-problem of the sensor and is deactivated -          // DEBUG_SENSOR_LOG(PSTR("CHIRP: auto-wake all")); -          // ChirpAutoWakeAll();       // this is only a wake-up call at the start of next read cycle -          chirp_next_job++;         // go on, next job should start in a second -          break; -          case 2: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read")); -          ChirpServiceAllSensors(0);   -          chirp_timeout_count = 11;  // wait 1.1 seconds,  -          chirp_next_job++; -          break; -          case 3: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read")); -          ChirpServiceAllSensors(1);  -          chirp_next_job++; -          break; -          case 4: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd")); -          ChirpServiceAllSensors(0);  -          chirp_timeout_count = 11;  // wait 1.1 seconds,  -          chirp_next_job++; -          break; -          case 5: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd")); -          ChirpServiceAllSensors(1);  -          chirp_next_job++; -          break; -          case 6: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read")); -          ChirpServiceAllSensors(2);  -          chirp_timeout_count = 11;  // wait 1.1 seconds,  -          chirp_next_job++; -          break; -          case 7: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read")); -          ChirpServiceAllSensors(3);  -          chirp_next_job++; -          break; -          case 8: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd")); -          ChirpServiceAllSensors(2); -          chirp_timeout_count = 11;  // wait 1.1 seconds,  -          chirp_next_job++; -          break; -          case 9: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd")); -          ChirpServiceAllSensors(3); -          chirp_next_job++; -          break;        -          case 10: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process")); -          ChirpServiceAllSensors(4); -          chirp_timeout_count = 90;  // wait 9 seconds,   -          chirp_next_job++; -          break; -          case 11: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read")); -          ChirpServiceAllSensors(5); -          chirp_timeout_count = 11;  // wait 1.1 seconds,  -          chirp_next_job++; -          break; -          case 12: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read")); -          ChirpServiceAllSensors(6); -          chirp_next_job++; -          break;      -          case 13: -          DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); -          break; -          case 14: -          if (Settings.tele_period > 16){ -              chirp_timeout_count = (Settings.tele_period - 17) * 10;  // sync it with the TELEPERIOD, we need about up to 17 seconds to measure -              DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); -            } -          else{ -            AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); -          } -          chirp_next_job = 1;                                 // back to step 1 -          break; -      } -  } -  else { -      chirp_timeout_count--;         // count down -  } + // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); + if(chirp_timeout_count == 0) { //countdown complete, now do something + switch(chirp_next_job) { + case 0: //this should only be called after driver initialization + DEBUG_SENSOR_LOG(PSTR("CHIRP: reset all")); + ChirpResetAll(); + chirp_timeout_count = 10; // wait a second + chirp_next_job++; + break; + case 1: // auto-sleep-wake seems to expose a fundamental I2C-problem of the sensor and is deactivated + // DEBUG_SENSOR_LOG(PSTR("CHIRP: auto-wake all")); + // ChirpAutoWakeAll(); // this is only a wake-up call at the start of next read cycle + chirp_next_job++; // go on, next job should start in a second + break; + case 2: + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read")); + ChirpServiceAllSensors(0); + chirp_timeout_count = 11; // wait 1.1 seconds, + chirp_next_job++; + break; + case 3: + DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read")); + ChirpServiceAllSensors(1); + chirp_next_job++; + break; + case 4: + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd")); + ChirpServiceAllSensors(0); + chirp_timeout_count = 11; // wait 1.1 seconds, + chirp_next_job++; + break; + case 5: + DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd")); + ChirpServiceAllSensors(1); + chirp_next_job++; + break; + case 6: + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read")); + ChirpServiceAllSensors(2); + chirp_timeout_count = 11; // wait 1.1 seconds, + chirp_next_job++; + break; + case 7: + DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read")); + ChirpServiceAllSensors(3); + chirp_next_job++; + break; + case 8: + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd")); + ChirpServiceAllSensors(2); + chirp_timeout_count = 11; // wait 1.1 seconds, + chirp_next_job++; + break; + case 9: + DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd")); + ChirpServiceAllSensors(3); + chirp_next_job++; + break; + case 10: + DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process")); + ChirpServiceAllSensors(4); + chirp_timeout_count = 90; // wait 9 seconds, + chirp_next_job++; + break; + case 11: + DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read")); + ChirpServiceAllSensors(5); + chirp_timeout_count = 11; // wait 1.1 seconds, + chirp_next_job++; + break; + case 12: + DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read")); + ChirpServiceAllSensors(6); + chirp_next_job++; + break; + case 13: + DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); + break; + case 14: + if (Settings.tele_period > 16){ + chirp_timeout_count = (Settings.tele_period - 17) * 10; // sync it with the TELEPERIOD, we need about up to 17 seconds to measure + DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); + } + else{ + AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); + } + chirp_next_job = 1; // back to step 1 + break; + } + } + else { + chirp_timeout_count--; // count down + } } /********************************************************************************************/ -// normaly in i18n.h +// normaly in i18n.h -#define D_JSON_MOISTURE "Moisture" +#define D_JSON_MOISTURE "Moisture" +#define D_JSON_DARKNESS "Darkness" -#ifdef USE_WEBSERVER -  // {s} = , {m} = , {e} =  +#ifdef USE_WEBSERVER + // {s} = , {m} = , {e} = - const char HTTP_SNS_MOISTURE[] PROGMEM = "{s} " D_JSON_MOISTURE ": {m}%s %{e}"; - const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address: {m}0x%x{e}" -                                          "{s} FW-version: {m}%s {e}";                                                                                            ; - const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; -#endif  // USE_WEBSERVER + const char HTTP_SNS_MOISTURE[] PROGMEM = "{s} " D_JSON_MOISTURE "{m}%s %{e}"; + const char HTTP_SNS_DARKNESS[] PROGMEM = "{s} " D_JSON_DARKNESS "{m}%s %{e}"; + const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address{m}0x%x{e}" + "{s} FW-version{m}%s {e}"; ; + const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; +#endif // USE_WEBSERVER /********************************************************************************************/ -void ChirpShow(bool json) +void ChirpShow(bool json) { -  for (uint32_t i = 0; i < chirp_found_sensors; i++) { -    if (chirp_sensor[i].version) { -      // convert double values to string -      char str_moisture[33];       -      dtostrfd(chirp_sensor[i].moisture, 0, str_moisture); -      char str_temperature[33]; -      double t_temperature = ((double) chirp_sensor[i].temperature )/10.0;    -      dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); -      char str_light[33];       -      dtostrfd(chirp_sensor[i].light, 0, str_light); -      char str_version[33];       -      dtostrfd(chirp_sensor[i].version, 0, str_version); -      if (json) { -        if(!chirp_sensor[i].explicitSleep){ -          ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":\"%s}"), -          chirp_name, i, str_moisture, str_temperature, str_light);} -        else { -          ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"), -          chirp_name, i); -        } -  #ifdef USE_DOMOTICZ -      if (0 == tele_period) { -              DomoticzTempHumSensor(str_temperature, str_moisture); -              DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); -        } -  #endif  // USE_DOMOTICZ -  #ifdef USE_WEBSERVER -      } else { -        WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); -        if (chirp_sensor[i].explicitSleep){ -          WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); -        } -        else { -          WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture); -          WSContentSend_PD(HTTP_SNS_ILLUMINANCE, " ", chirp_sensor[i].light); -          WSContentSend_PD(HTTP_SNS_TEMP, " ",str_temperature, TempUnit());    -        } -   -  #endif  // USE_WEBSERVER -      } -    } -  }   + for (uint32_t i = 0; i < chirp_found_sensors; i++) { + if (chirp_sensor[i].version) { + // convert double values to string + char str_moisture[33]; + dtostrfd(chirp_sensor[i].moisture, 0, str_moisture); + char str_temperature[33]; + double t_temperature = ((double) chirp_sensor[i].temperature )/10.0; + dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); + char str_light[33]; + dtostrfd(chirp_sensor[i].light, 0, str_light); + char str_version[33]; + dtostrfd(chirp_sensor[i].version, 0, str_version); + if (json) { + if(!chirp_sensor[i].explicitSleep) { + ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s"),chirp_name, i, str_moisture); + if(chirp_sensor[i].temperature!=-1){ // this is the error code -> no temperature + ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"),str_temperature); + } + ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":\"%s}"),str_light); + } + else { + ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"),chirp_name, i); + } + #ifdef USE_DOMOTICZ + if (0 == tele_period) { + DomoticzTempHumSensor(str_temperature, str_moisture); + DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); + } + #endif // USE_DOMOTICZ + #ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); + if (chirp_sensor[i].explicitSleep){ + WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); + } + else { + WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture); + WSContentSend_PD(HTTP_SNS_DARKNESS, str_light); + if(chirp_sensor[i].temperature!=-1){ // this is the error code -> no temperature + WSContentSend_PD(HTTP_SNS_TEMP, " ",str_temperature, TempUnit()); + } + } + + #endif // USE_WEBSERVER + } + } + } } /*********************************************************************************************\ - * check the Chirp commands + * check the Chirp commands \*********************************************************************************************/ -bool ChirpCmd(void) { -  char command[CMDSZ]; -  bool serviced = true; -  uint8_t disp_len = strlen(D_CMND_CHIRP); +bool ChirpCmd(void) { + char command[CMDSZ]; + bool serviced = true; + uint8_t disp_len = strlen(D_CMND_CHIRP); -  if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) {  // prefix -    int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands); + if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) { // prefix + int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands); -    switch (command_code) { -      case CMND_CHIRP_SELECT: -      case CMND_CHIRP_SET: -        if (XdrvMailbox.data_len > 0) { -          if (command_code == CMND_CHIRP_SELECT)  { ChirpSelect(XdrvMailbox.payload); }                       //select active sensor, i.e. for wake, sleep or reset -          if (command_code == CMND_CHIRP_SET)     { ChirpSet((uint8_t)XdrvMailbox.payload); }                 //set and change I2C-address of selected sensor -        Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload); -        } -        else { -          if (command_code == CMND_CHIRP_SELECT)  { ChirpSelect(255); }                                       //show active sensor -        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); -        }      -        break; -      case CMND_CHIRP_SCAN:  -      case CMND_CHIRP_SLEEP: -      case CMND_CHIRP_WAKE: -      case CMND_CHIRP_RESET: -        if (command_code == CMND_CHIRP_SCAN)     {  chirp_next_job = 0; -                                                    ChirpDetect(); }                                            // this will re-init the sensor array -        if (command_code == CMND_CHIRP_SLEEP)    {  chirp_sensor[chirp_current].explicitSleep = true;         // we do not touch this sensor in the read functions -                                                    ChirpSleep(chirp_sensor[chirp_current].address); } -        if (command_code == CMND_CHIRP_WAKE)     {  chirp_sensor[chirp_current].explicitSleep = false;        // back in action -                                                    ChirpReadVersion(chirp_sensor[chirp_current].address); }  // just use read version as wakeup call                                          -        if (command_code == CMND_CHIRP_RESET)    { ChirpReset(chirp_sensor[chirp_current].address); } -        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); -        break; -      default: -        // else for Unknown command -        serviced = false; -      break; -    } -  } -  return serviced; + switch (command_code) { + case CMND_CHIRP_SELECT: + case CMND_CHIRP_SET: + if (XdrvMailbox.data_len > 0) { + if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(XdrvMailbox.payload); } //select active sensor, i.e. for wake, sleep or reset + if (command_code == CMND_CHIRP_SET) { ChirpSet((uint8_t)XdrvMailbox.payload); } //set and change I2C-address of selected sensor + Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload); + } + else { + if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(255); } //show active sensor + Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); + } + break; + case CMND_CHIRP_SCAN: + case CMND_CHIRP_SLEEP: + case CMND_CHIRP_WAKE: + case CMND_CHIRP_RESET: + if (command_code == CMND_CHIRP_SCAN) { chirp_next_job = 0; + ChirpDetect(); } // this will re-init the sensor array + if (command_code == CMND_CHIRP_SLEEP) { chirp_sensor[chirp_current].explicitSleep = true; // we do not touch this sensor in the read functions + ChirpSleep(chirp_sensor[chirp_current].address); } + if (command_code == CMND_CHIRP_WAKE) { chirp_sensor[chirp_current].explicitSleep = false; // back in action + ChirpReadVersion(chirp_sensor[chirp_current].address); } // just use read version as wakeup call + if (command_code == CMND_CHIRP_RESET) { ChirpReset(chirp_sensor[chirp_current].address); } + Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); + break; + default: + // else for Unknown command + serviced = false; + break; + } + } + return serviced; } /*********************************************************************************************\ - * Interface + * Interface \*********************************************************************************************/ -bool Xsns48(uint8_t function) +bool Xsns48(uint8_t function) { -  bool result = false; + bool result = false; -  if (i2c_flg) {   -    switch (function) { -      case FUNC_INIT: -        ChirpDetect();         // We can call CHIRPSCAN later to re-detect -        break; -      case FUNC_EVERY_100_MSECOND: -        if(chirp_found_sensors > 0){ -          ChirpEvery100MSecond(); -        }     -        break; -      case FUNC_COMMAND: -        result = ChirpCmd();   -        break; -      case FUNC_JSON_APPEND: -        ChirpShow(1); -        chirp_next_job = 14; // TELE done, now compute time for next measure cycle -        break; -#ifdef USE_WEBSERVER -      case FUNC_WEB_SENSOR: -        ChirpShow(0); -        break; -#endif  // USE_WEBSERVER -    } -  } -  return result; + if (i2c_flg) { + switch (function) { + case FUNC_INIT: + ChirpDetect(); // We can call CHIRPSCAN later to re-detect + break; + case FUNC_EVERY_100_MSECOND: + if(chirp_found_sensors > 0){ + ChirpEvery100MSecond(); + } + break; + case FUNC_COMMAND: + result = ChirpCmd(); + break; + case FUNC_JSON_APPEND: + ChirpShow(1); + chirp_next_job = 14; // TELE done, now compute time for next measure cycle + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + ChirpShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; } -#endif  // USE_CHIRP -#endif  // USE_I2C +#endif // USE_CHIRP +#endif // USE_I2C From a066acd7f2226c23c7feb337df62c065342fa60c Mon Sep 17 00:00:00 2001 From: Staars Date: Wed, 18 Sep 2019 21:06:14 +0200 Subject: [PATCH 3/6] remove a double quote from TELE-message --- sonoff/xsns_48_chirp.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index 53a5e3768..283128b29 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -23,7 +23,7 @@ 1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS changed - do not publish missing temperature reads - added - now really support for the (slower) CHIRP-Sensor + added - now really support the (slower) CHIRP-Sensor --- 1.0.0.0 20190608 started - further development by Christian Baars - https://github.com/Staars/Sonoff-Tasmota forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota @@ -418,7 +418,7 @@ void ChirpShow(bool json) if(chirp_sensor[i].temperature!=-1){ // this is the error code -> no temperature ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"),str_temperature); } - ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":\"%s}"),str_light); + ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":%s}"),str_light); } else { ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"),chirp_name, i); From ab70dd2755c75a8ed64151898fccd8a70d248ac3 Mon Sep 17 00:00:00 2001 From: Staars Date: Sun, 29 Sep 2019 13:27:50 +0200 Subject: [PATCH 4/6] various fixes for the Chirp-sensor --- sonoff/xsns_48_chirp.ino | 48 ++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index 283128b29..872478b8d 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -21,9 +21,10 @@ -------------------------------------------------------------------------------------------- 1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads + changed - double send address change only for fw>0x25 changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS - changed - do not publish missing temperature reads - added - now really support the (slower) CHIRP-Sensor + changed - do not publish missing temperature reads, show fw-version as hex + added - now really support the (slower) CHIRP!-Sensor --- 1.0.0.0 20190608 started - further development by Christian Baars - https://github.com/Staars/Sonoff-Tasmota forked - from arendst/tasmota - https://github.com/arendst/Sonoff-Tasmota @@ -36,7 +37,8 @@ #ifdef USE_CHIRP /*********************************************************************************************\ - * CHIRP - Soil moisture sensor + * CHIRP - Chirp!-sensor and I2C-soil-moisture-sensor + * !! The I2C-soil-moisture-sensor is the preferred one !! * * I2C Address: 0x20 - standard address, is changeable \*********************************************************************************************/ @@ -82,7 +84,7 @@ enum CHIRP_Commands { // commands useable in con #define CHIRP_GET_LIGHT 0x04 // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated #define CHIRP_GET_TEMPERATURE 0x05 // 16 bit, read #define CHIRP_RESET 0x06 // no value, write -#define CHIRP_GET_VERSION 0x07 // 8 bit, read, -> 22 means 2.2 +#define CHIRP_GET_VERSION 0x07 // 8 bit, read, -> 0x22 means 2.2 #define CHIRP_SLEEP 0x08 // no value, write #define CHIRP_GET_BUSY 0x09 // 8 bit, read, -> 1 = busy, 0 = otherwise @@ -187,24 +189,35 @@ void ChirpSelect(uint8_t sensor) { } } -/********************************************************************************************/ +/******************************************************************************************************************/ uint8_t ChirpReadVersion(uint8_t addr) { - return (I2cRead8(addr, CHIRP_GET_VERSION)); + return (I2cRead8(addr, CHIRP_GET_VERSION)); // the Chirp!-sensor does not provide fw-version and we will get 255 } -/********************************************************************************************/ +/******************************************************************************************************************/ bool ChirpSet(uint8_t addr) { if(addr < 128){ if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ - I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); // two calls are needed for sensor firmware version 2.6 + if(chirp_sensor[chirp_current].version>0x25 && chirp_sensor[chirp_current].version != 255){ + delay(5); + I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr); + // two calls are needed for sensor firmware version 2.6, but maybe dangerous before + } DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr); ChirpReset(chirp_sensor[chirp_current].address); chirp_sensor[chirp_current].address = addr; + chirp_timeout_count = 10; + chirp_next_job = 0; + if(chirp_sensor[chirp_current].version == 255){ // this should be Chirp! and it seems to need a power cycle (or RESET to GND) + AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: wrote new address %u, please power off device"), addr); + chirp_sensor[chirp_current].version == 0; // make it "invisible" + } return true; } } + AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: address %u incorrect and not used"), addr); return false; } @@ -222,11 +235,12 @@ bool ChirpScan() { AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address); if(chirp_found_sensors 16){ chirp_timeout_count = (Settings.tele_period - 17) * 10; // sync it with the TELEPERIOD, we need about up to 17 seconds to measure - DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); + DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period); } else{ AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); + // we could overwrite it to i.e. 20 seconds here } chirp_next_job = 1; // back to step 1 break; @@ -408,10 +423,15 @@ void ChirpShow(bool json) char str_temperature[33]; double t_temperature = ((double) chirp_sensor[i].temperature )/10.0; dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); - char str_light[33]; + char str_light[33]; dtostrfd(chirp_sensor[i].light, 0, str_light); - char str_version[33]; - dtostrfd(chirp_sensor[i].version, 0, str_version); + char str_version[7]; + if(chirp_sensor[i].version == 255){ + strncpy_P(str_version, PSTR("Chirp!"), sizeof(str_version)); + } + else{ + sprintf(str_version, "%x", chirp_sensor[i].version); + } if (json) { if(!chirp_sensor[i].explicitSleep) { ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s"),chirp_name, i, str_moisture); @@ -426,7 +446,7 @@ void ChirpShow(bool json) #ifdef USE_DOMOTICZ if (0 == tele_period) { DomoticzTempHumSensor(str_temperature, str_moisture); - DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); + DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); // this is not LUX!! } #endif // USE_DOMOTICZ #ifdef USE_WEBSERVER From 6da17ccb6b47ce5c888195120d827ebe1d241405 Mon Sep 17 00:00:00 2001 From: Staars Date: Sun, 29 Sep 2019 18:35:02 +0200 Subject: [PATCH 5/6] last fixes for the Chirp-sensor --- sonoff/xsns_48_chirp.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index 872478b8d..b0246566f 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -426,7 +426,7 @@ void ChirpShow(bool json) char str_light[33]; dtostrfd(chirp_sensor[i].light, 0, str_light); char str_version[7]; - if(chirp_sensor[i].version == 255){ + if(chirp_sensor[i].version == 0xff){ strncpy_P(str_version, PSTR("Chirp!"), sizeof(str_version)); } else{ From e6824ff903ec47865d024793796e5a6f54925f69 Mon Sep 17 00:00:00 2001 From: Staars Date: Sun, 29 Sep 2019 18:38:14 +0200 Subject: [PATCH 6/6] remove #define USE_CHIRP --- sonoff/xsns_48_chirp.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/sonoff/xsns_48_chirp.ino b/sonoff/xsns_48_chirp.ino index b0246566f..c2bf08f1d 100644 --- a/sonoff/xsns_48_chirp.ino +++ b/sonoff/xsns_48_chirp.ino @@ -32,7 +32,6 @@ */ -#define USE_CHIRP #ifdef USE_I2C #ifdef USE_CHIRP