name it DARKNESS, handle non-reading of temperature, small bugfixes

This commit is contained in:
Staars 2019-09-18 20:57:35 +02:00
parent a02c733073
commit eb8539dd91

View File

@ -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 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 it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version. (at your option) any later version.
  This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details. GNU General Public License for more details.
  You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
  -------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
  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 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 changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS
  --- changed - do not publish missing temperature reads
  1.0.0.0 20190608  started   - further development by Christian Baars  - https://github.com/Staars/Sonoff-Tasmota added - now really support for the (slower) CHIRP-Sensor
                    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.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 #define USE_CHIRP
#ifdef USE_CHIRP #ifdef USE_I2C
#ifdef USE_CHIRP
/*********************************************************************************************\ /*********************************************************************************************\
 * CHIRP - Soil moisture sensor * CHIRP - Soil moisture sensor
 *  *
 * I2C Address: 0x20 - standard address, is changeable * I2C Address: 0x20 - standard address, is changeable
\*********************************************************************************************/ \*********************************************************************************************/
#define XSNS_48                     48 #define XSNS_48 48
#define CHIRP_MAX_SENSOR_COUNT      3               // 127 is expectectd to be the max number #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_NVALUE[] PROGMEM = "{\"" D_CMND_CHIRP "%s\":%d}";
const char S_JSON_CHIRP_COMMAND[] PROGMEM        = "{\"" D_CMND_CHIRP "%s\"}"; const char S_JSON_CHIRP_COMMAND[] PROGMEM = "{\"" D_CMND_CHIRP "%s\"}";
const char kCHIRP_Commands[] PROGMEM             = "Select|Set|Scan|Reset|Sleep|Wake"; 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 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_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_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_SCAN, // scan the I2C bus for one or more chirp sensors
  CMND_CHIRP_RESET,                                   // CHIRPReset, a fresh and default restart CMND_CHIRP_RESET, // CHIRPReset, a fresh and default restart
  CMND_CHIRP_SLEEP,                                   // put sensor to sleep CMND_CHIRP_SLEEP, // put sensor to sleep
  CMND_CHIRP_WAKE };                                  // wake sensor by reading firmware version CMND_CHIRP_WAKE }; // wake sensor by reading firmware version
/*********************************************************************************************\ /*********************************************************************************************\
 * command defines * command defines
\*********************************************************************************************/ \*********************************************************************************************/
#define CHIRP_GET_CAPACITANCE       0x00            // 16 bit, read #define CHIRP_GET_CAPACITANCE 0x00 // 16 bit, read
#define CHIRP_SET_ADDRESS           0x01            // 8 bit,  write #define CHIRP_SET_ADDRESS 0x01 // 8 bit, write
#define CHIRP_GET_ADDRESS           0x02            // 8 bit,  read #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_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_LIGHT 0x04 // 16 bit, read, -> higher value means darker environment, noisy data, not calibrated
#define CHIRP_GET_TEMPERATURE       0x05            // 16 bit, read #define CHIRP_GET_TEMPERATURE 0x05 // 16 bit, read
#define CHIRP_RESET                 0x06            // no value, write #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, -> 22 means 2.2
#define CHIRP_SLEEP                 0x08            // no value, write #define CHIRP_SLEEP 0x08 // no value, write
#define CHIRP_GET_BUSY              0x09            // 8 bit, read, -> 1 = busy, 0 = otherwise #define CHIRP_GET_BUSY 0x09 // 8 bit, read, -> 1 = busy, 0 = otherwise
/*********************************************************************************************\ /*********************************************************************************************\
 * helper function * helper function
\*********************************************************************************************/ \*********************************************************************************************/
void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) { void ChirpWriteI2CRegister(uint8_t addr, uint8_t reg) {
  Wire.beginTransmission(addr); Wire.beginTransmission(addr);
  Wire.write(reg); Wire.write(reg);
  Wire.endTransmission();  Wire.endTransmission();
} // now the original CHIRP needs 1100 ms delay } // now the original CHIRP needs 1100 ms delay
uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) { uint16_t ChirpFinishReadI2CRegister16bit(uint8_t addr) {
  Wire.requestFrom(addr,(uint8_t)2); Wire.requestFrom(addr,(uint8_t)2);
  uint16_t t = Wire.read() << 8; uint16_t t = Wire.read() << 8;
  t = t | Wire.read(); t = t | Wire.read();
  return t; return t;
} }
/********************************************************************************************/ /********************************************************************************************/
// globals // globals
uint8_t    chirp_current        = 0;    // current selected/active sensor uint8_t chirp_current = 0; // current selected/active sensor
uint8_t    chirp_found_sensors  = 0;    // number of found sensors uint8_t chirp_found_sensors = 0; // number of found sensors
char       chirp_name[7]; char chirp_name[7];
uint8_t    chirp_next_job       = 0;    //0=reset, 1=auto-wake, 2-9 = various measure steps; 10 = TELE done 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) uint32_t chirp_timeout_count = 0; //is handled every second, so value is equal to seconds (it is a slow sensor)
#pragma pack(1) #pragma pack(1)
struct ChirpSensor_t{ struct ChirpSensor_t{
    uint16_t   moisture = 0;      // shall hold post-processed data, if implemented uint16_t moisture = 0; // shall hold post-processed data, if implemented
    uint16_t   light = 0;         // light level, maybe already postprocessed depending on the firmware uint16_t light = 0; // light level, maybe already postprocessed depending on the firmware
    int16_t    temperature= 0;    // temperature in degrees CELSIUS * 10 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 version = 0; // firmware-version
    uint8_t    address:7;         // we need only 7bit so... uint8_t address:7; // we need only 7bit so...
    uint8_t    explicitSleep:1;   // there is a free bit to play with ;) 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) { void ChirpReset(uint8_t addr) {
    ChirpWriteI2CRegister(addr, CHIRP_RESET); ChirpWriteI2CRegister(addr, CHIRP_RESET);
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpResetAll(void) { void ChirpResetAll(void) {
    for (uint32_t i = 0; i < chirp_found_sensors; i++) { for (uint32_t i = 0; i < chirp_found_sensors; i++) {
      if (chirp_sensor[i].version) {  if (chirp_sensor[i].version) {
        ChirpReset(chirp_sensor[i].address); ChirpReset(chirp_sensor[i].address);
        } }
    } }
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpClockSet() { // set I2C for this slow sensor void ChirpClockSet() { // set I2C for this slow sensor
    Wire.setClockStretchLimit(4000); Wire.setClockStretchLimit(4000);
    Wire.setClock(50000); Wire.setClock(50000);
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpSleep(uint8_t addr) { void ChirpSleep(uint8_t addr) {
    ChirpWriteI2CRegister(addr, CHIRP_SLEEP); ChirpWriteI2CRegister(addr, CHIRP_SLEEP);
} }
/********************************************************************************************/ /********************************************************************************************/
// void ChirpSleepAll(void) { // void ChirpSleepAll(void) {
//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { // for (uint32_t i = 0; i < chirp_found_sensors; i++) {
//       if (chirp_sensor[i].version) {  // if (chirp_sensor[i].version) {
//         ChirpSleep(chirp_sensor[i].address); // ChirpSleep(chirp_sensor[i].address);
//         } // }
//     } // }
// } // }
// /********************************************************************************************/ // /********************************************************************************************/
// void ChirpAutoWakeAll(void) { // void ChirpAutoWakeAll(void) {
//     for (uint32_t i = 0; i < chirp_found_sensors; i++) { // for (uint32_t i = 0; i < chirp_found_sensors; i++) {
//       if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  // if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {
//         ChirpReadVersion(chirp_sensor[i].address); // ChirpReadVersion(chirp_sensor[i].address);
//         } // }
//     } // }
// } // }
/********************************************************************************************/ /********************************************************************************************/
void ChirpSelect(uint8_t sensor) { void ChirpSelect(uint8_t sensor) {
  if(sensor < chirp_found_sensors) { //TODO: show some infos if(sensor < chirp_found_sensors) { //TODO: show some infos
    chirp_current = sensor; chirp_current = sensor;
    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current); DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u now active."), chirp_current);
  } }
  if (sensor == 255) { if (sensor == 255) {
    DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address); DEBUG_SENSOR_LOG(PSTR("CHIRP: Sensor %u active at address 0x%x."), chirp_current, chirp_sensor[chirp_current].address);
  } }
} }
/********************************************************************************************/ /********************************************************************************************/
// bool ChirpMeasureLight(void) { uint8_t ChirpReadVersion(uint8_t addr) {
//   for (uint32_t i = 0; i < chirp_found_sensors; i++) { return (I2cRead8(addr, CHIRP_GET_VERSION));
//     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));
} }
/********************************************************************************************/ /********************************************************************************************/
bool ChirpSet(uint8_t addr) { bool ChirpSet(uint8_t addr) {
  if(addr < 128){ if(addr < 128){
    if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){ 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 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); DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr);
      ChirpReset(chirp_sensor[chirp_current].address); ChirpReset(chirp_sensor[chirp_current].address);
      chirp_sensor[chirp_current].address = addr; chirp_sensor[chirp_current].address = addr;
      return true; return true;
    } }
  } }
  return false; return false;
} }
/********************************************************************************************/ /********************************************************************************************/
bool ChirpScan() { bool ChirpScan() {
    ChirpClockSet(); ChirpClockSet();
    chirp_found_sensors = 0; chirp_found_sensors = 0;
    for (uint8_t address = 1; address <= 127; address++) { for (uint8_t address = 1; address <= 127; address++) {
      chirp_sensor[chirp_found_sensors].version = 0; chirp_sensor[chirp_found_sensors].version = 0;
      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address);
      delay(2); delay(2);
      chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address); chirp_sensor[chirp_found_sensors].version = ChirpReadVersion(address);
      if(chirp_sensor[chirp_found_sensors].version > 0) { if(chirp_sensor[chirp_found_sensors].version > 0) {
        AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address);     AddLog_P2(LOG_LEVEL_DEBUG, S_LOG_I2C_FOUND_AT, "CHIRP:", address);
        if(chirp_found_sensors<CHIRP_MAX_SENSOR_COUNT){ if(chirp_found_sensors<CHIRP_MAX_SENSOR_COUNT){
          chirp_sensor[chirp_found_sensors].address = address; // push next sensor, as long as there is space in the array chirp_sensor[chirp_found_sensors].address = address; // push next sensor, as long as there is space in the array
          AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: fw %u"), chirp_sensor[chirp_found_sensors].version); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: fw %u"), chirp_sensor[chirp_found_sensors].version);
        } }
        chirp_found_sensors++; chirp_found_sensors++;
      } }
    } }
    AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Found %u CHIRP sensor(s)."), chirp_found_sensors); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Found %u CHIRP sensor(s)."), chirp_found_sensors);
    if (chirp_found_sensors == 0) {return false;} if (chirp_found_sensors == 0) {return false;}
    else {return true;} else {return true;}
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpDetect(void) void ChirpDetect(void)
{ {
  if (chirp_next_job > 0) { if (chirp_next_job > 0) {
    return; return;
  } }
  DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ...")); DEBUG_SENSOR_LOG(PSTR("CHIRP: scan will start ..."));
  if (ChirpScan()) { if (ChirpScan()) {
    uint8_t chirp_model = 0;  // TODO: ?? uint8_t chirp_model = 0; // TODO: ??
    GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes); GetTextIndexed(chirp_name, sizeof(chirp_name), chirp_model, kChirpTypes);
  } }
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpServiceAllSensors(uint8_t job){ void ChirpServiceAllSensors(uint8_t job){
  for (uint32_t i = 0; i < chirp_found_sensors; i++) { for (uint32_t i = 0; i < chirp_found_sensors; i++) {
    if (chirp_sensor[i].version && !chirp_sensor[i].explicitSleep) {  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); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare for sensor at address 0x%x"), chirp_sensor[i].address);
      switch(job){ switch(job){
        case 0: case 0:
        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE); ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_CAPACITANCE);
        break; break;
        case 1: case 1:
        chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); chirp_sensor[i].moisture = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address);
        break; break;
        case 2: case 2:
        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE); ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_TEMPERATURE);
        break; break;
        case 3: case 3:
        chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); chirp_sensor[i].temperature = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address);
        break; break;
        case 4: case 4:
        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT); ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_MEASURE_LIGHT);
        break; break;
        case 5: case 5:
        ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT); ChirpWriteI2CRegister(chirp_sensor[i].address, CHIRP_GET_LIGHT);
        break; break;
        case 6: case 6:
        chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address); chirp_sensor[i].light = ChirpFinishReadI2CRegister16bit(chirp_sensor[i].address);
        break; break;
        default: default:
        break; break;
      } }
    } }
  }   }
} }
/********************************************************************************************/ /********************************************************************************************/
void ChirpEvery100MSecond(void) void ChirpEvery100MSecond(void)
{ {
  // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); // DEBUG_SENSOR_LOG(PSTR("CHIRP: every second"));
  if(chirp_timeout_count == 0) {    //countdown complete, now do something if(chirp_timeout_count == 0) { //countdown complete, now do something
      switch(chirp_next_job) { switch(chirp_next_job) {
          case 0:                   //this should only be called after driver initialization case 0: //this should only be called after driver initialization
          DEBUG_SENSOR_LOG(PSTR( "CHIRP: reset all")); DEBUG_SENSOR_LOG(PSTR("CHIRP: reset all"));
          ChirpResetAll(); ChirpResetAll();
          chirp_timeout_count = 10; // wait a second chirp_timeout_count = 10; // wait a second
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 1:                   // auto-sleep-wake seems to expose a fundamental I2C-problem of the sensor and is deactivated 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")); // DEBUG_SENSOR_LOG(PSTR("CHIRP: auto-wake all"));
          // ChirpAutoWakeAll();       // this is only a wake-up call at the start of next read cycle // 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 chirp_next_job++; // go on, next job should start in a second
          break; break;
          case 2: case 2:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read"));
          ChirpServiceAllSensors(0);   ChirpServiceAllSensors(0);
          chirp_timeout_count = 11;  // wait 1.1 seconds,  chirp_timeout_count = 11; // wait 1.1 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 3: case 3:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read"));
          ChirpServiceAllSensors(1);  ChirpServiceAllSensors(1);
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 4: case 4:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd")); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare moisture read - 2nd"));
          ChirpServiceAllSensors(0);  ChirpServiceAllSensors(0);
          chirp_timeout_count = 11;  // wait 1.1 seconds,  chirp_timeout_count = 11; // wait 1.1 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 5: case 5:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd")); DEBUG_SENSOR_LOG(PSTR("CHIRP: finish moisture read - 2nd"));
          ChirpServiceAllSensors(1);  ChirpServiceAllSensors(1);
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 6: case 6:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read"));
          ChirpServiceAllSensors(2);  ChirpServiceAllSensors(2);
          chirp_timeout_count = 11;  // wait 1.1 seconds,  chirp_timeout_count = 11; // wait 1.1 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 7: case 7:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read"));
          ChirpServiceAllSensors(3);  ChirpServiceAllSensors(3);
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 8: case 8:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd")); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare temperature read - 2nd"));
          ChirpServiceAllSensors(2); ChirpServiceAllSensors(2);
          chirp_timeout_count = 11;  // wait 1.1 seconds,  chirp_timeout_count = 11; // wait 1.1 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 9: case 9:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd")); DEBUG_SENSOR_LOG(PSTR("CHIRP: finish temperature read - 2nd"));
          ChirpServiceAllSensors(3); ChirpServiceAllSensors(3);
          chirp_next_job++; chirp_next_job++;
          break;        break;
          case 10: case 10:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process")); DEBUG_SENSOR_LOG(PSTR("CHIRP: start light measure process"));
          ChirpServiceAllSensors(4); ChirpServiceAllSensors(4);
          chirp_timeout_count = 90;  // wait 9 seconds,   chirp_timeout_count = 90; // wait 9 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 11: case 11:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: prepare light read"));
          ChirpServiceAllSensors(5); ChirpServiceAllSensors(5);
          chirp_timeout_count = 11;  // wait 1.1 seconds,  chirp_timeout_count = 11; // wait 1.1 seconds,
          chirp_next_job++; chirp_next_job++;
          break; break;
          case 12: case 12:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read")); DEBUG_SENSOR_LOG(PSTR("CHIRP: finish light read"));
          ChirpServiceAllSensors(6); ChirpServiceAllSensors(6);
          chirp_next_job++; chirp_next_job++;
          break;      break;
          case 13: case 13:
          DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE"));
          break; break;
          case 14: case 14:
          if (Settings.tele_period > 16){ 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 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: %u, tele: %u"), chirp_timeout_count, Settings.tele_period);
            } }
          else{ else{
            AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !")); AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !"));
          } }
          chirp_next_job = 1;                                 // back to step 1 chirp_next_job = 1; // back to step 1
          break; break;
      } }
  } }
  else { else {
      chirp_timeout_count--;         // count down 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 #ifdef USE_WEBSERVER
  // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr> // {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
 const char HTTP_SNS_MOISTURE[] PROGMEM = "{s} " D_JSON_MOISTURE ": {m}%s %{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}" const char HTTP_SNS_DARKNESS[] PROGMEM = "{s} " D_JSON_DARKNESS "{m}%s %{e}";
                                          "{s} FW-version: {m}%s {e}";                                                                                            ; const char HTTP_SNS_CHIRPVER[] PROGMEM = "{s} CHIRP-sensor %u at address{m}0x%x{e}"
 const char HTTP_SNS_CHIRPSLEEP[] PROGMEM = "{s} {m} is sleeping ...{e}"; "{s} FW-version{m}%s {e}"; ;
#endif  // USE_WEBSERVER 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++) { for (uint32_t i = 0; i < chirp_found_sensors; i++) {
    if (chirp_sensor[i].version) { if (chirp_sensor[i].version) {
      // convert double values to string // convert double values to string
      char str_moisture[33];       char str_moisture[33];
      dtostrfd(chirp_sensor[i].moisture, 0, str_moisture); dtostrfd(chirp_sensor[i].moisture, 0, str_moisture);
      char str_temperature[33]; char str_temperature[33];
      double t_temperature = ((double) chirp_sensor[i].temperature )/10.0;    double t_temperature = ((double) chirp_sensor[i].temperature )/10.0;
      dtostrfd(t_temperature, Settings.flag2.temperature_resolution, str_temperature); 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); dtostrfd(chirp_sensor[i].light, 0, str_light);
      char str_version[33];       char str_version[33];
      dtostrfd(chirp_sensor[i].version, 0, str_version); dtostrfd(chirp_sensor[i].version, 0, str_version);
      if (json) { if (json) {
        if(!chirp_sensor[i].explicitSleep){ if(!chirp_sensor[i].explicitSleep) {
          ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s,\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":\"%s}"), ResponseAppend_P(PSTR(",\"%s%u\":{\"" D_JSON_MOISTURE "\":%s"),chirp_name, i, str_moisture);
          chirp_name, i, str_moisture, str_temperature, str_light);} if(chirp_sensor[i].temperature!=-1){ // this is the error code -> no temperature
        else { ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"),str_temperature);
          ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"), }
          chirp_name, i); ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":\"%s}"),str_light);
        } }
  #ifdef USE_DOMOTICZ else {
      if (0 == tele_period) { ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"),chirp_name, i);
              DomoticzTempHumSensor(str_temperature, str_moisture); }
              DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); #ifdef USE_DOMOTICZ
        } if (0 == tele_period) {
  #endif  // USE_DOMOTICZ DomoticzTempHumSensor(str_temperature, str_moisture);
  #ifdef USE_WEBSERVER DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light);
      } else { }
        WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version); #endif // USE_DOMOTICZ
        if (chirp_sensor[i].explicitSleep){ #ifdef USE_WEBSERVER
          WSContentSend_PD(HTTP_SNS_CHIRPSLEEP); } else {
        } WSContentSend_PD(HTTP_SNS_CHIRPVER, i, chirp_sensor[i].address, str_version);
        else { if (chirp_sensor[i].explicitSleep){
          WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture); WSContentSend_PD(HTTP_SNS_CHIRPSLEEP);
          WSContentSend_PD(HTTP_SNS_ILLUMINANCE, " ", chirp_sensor[i].light); }
          WSContentSend_PD(HTTP_SNS_TEMP, " ",str_temperature, TempUnit());    else {
        } WSContentSend_PD(HTTP_SNS_MOISTURE, str_moisture);
   WSContentSend_PD(HTTP_SNS_DARKNESS, str_light);
  #endif  // USE_WEBSERVER 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) { bool ChirpCmd(void) {
  char command[CMDSZ]; char command[CMDSZ];
  bool serviced = true; bool serviced = true;
  uint8_t disp_len = strlen(D_CMND_CHIRP); uint8_t disp_len = strlen(D_CMND_CHIRP);
  if (!strncasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_CHIRP), disp_len)) {  // prefix 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); int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic + disp_len, kCHIRP_Commands);
    switch (command_code) { switch (command_code) {
      case CMND_CHIRP_SELECT: case CMND_CHIRP_SELECT:
      case CMND_CHIRP_SET: case CMND_CHIRP_SET:
        if (XdrvMailbox.data_len > 0) { 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_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 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); Response_P(S_JSON_CHIRP_COMMAND_NVALUE, command, XdrvMailbox.payload);
        } }
        else { else {
          if (command_code == CMND_CHIRP_SELECT)  { ChirpSelect(255); }                                       //show active sensor if (command_code == CMND_CHIRP_SELECT) { ChirpSelect(255); } //show active sensor
        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload);
        }      }
        break; break;
      case CMND_CHIRP_SCAN:  case CMND_CHIRP_SCAN:
      case CMND_CHIRP_SLEEP: case CMND_CHIRP_SLEEP:
      case CMND_CHIRP_WAKE: case CMND_CHIRP_WAKE:
      case CMND_CHIRP_RESET: case CMND_CHIRP_RESET:
        if (command_code == CMND_CHIRP_SCAN)     {  chirp_next_job = 0; if (command_code == CMND_CHIRP_SCAN) { chirp_next_job = 0;
                                                    ChirpDetect(); }                                            // this will re-init the sensor array 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 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); } ChirpSleep(chirp_sensor[chirp_current].address); }
        if (command_code == CMND_CHIRP_WAKE)     {  chirp_sensor[chirp_current].explicitSleep = false;        // back in action 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                                          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); } if (command_code == CMND_CHIRP_RESET) { ChirpReset(chirp_sensor[chirp_current].address); }
        Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload); Response_P(S_JSON_CHIRP_COMMAND, command, XdrvMailbox.payload);
        break; break;
      default: default:
        // else for Unknown command // else for Unknown command
        serviced = false; serviced = false;
      break; break;
    } }
  } }
  return serviced; return serviced;
} }
/*********************************************************************************************\ /*********************************************************************************************\
 * Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
bool Xsns48(uint8_t function) bool Xsns48(uint8_t function)
{ {
  bool result = false; bool result = false;
  if (i2c_flg) {   if (i2c_flg) {
    switch (function) { switch (function) {
      case FUNC_INIT: case FUNC_INIT:
        ChirpDetect();         // We can call CHIRPSCAN later to re-detect ChirpDetect(); // We can call CHIRPSCAN later to re-detect
        break; break;
      case FUNC_EVERY_100_MSECOND: case FUNC_EVERY_100_MSECOND:
        if(chirp_found_sensors > 0){ if(chirp_found_sensors > 0){
          ChirpEvery100MSecond(); ChirpEvery100MSecond();
        }     }
        break; break;
      case FUNC_COMMAND: case FUNC_COMMAND:
        result = ChirpCmd();   result = ChirpCmd();
        break; break;
      case FUNC_JSON_APPEND: case FUNC_JSON_APPEND:
        ChirpShow(1); ChirpShow(1);
        chirp_next_job = 14; // TELE done, now compute time for next measure cycle chirp_next_job = 14; // TELE done, now compute time for next measure cycle
        break; break;
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
      case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR:
        ChirpShow(0); ChirpShow(0);
        break; break;
#endif  // USE_WEBSERVER #endif // USE_WEBSERVER
    } }
  } }
  return result; return result;
} }
#endif  // USE_CHIRP #endif // USE_CHIRP
#endif  // USE_I2C #endif // USE_I2C