2019-08-06 20:48:55 +01:00
|
|
|
/*
|
2019-09-18 19:57:35 +01:00
|
|
|
xsns_48_chirp.ino - soil moisture sensor support for Sonoff-Tasmota
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
Copyright (C) 2019 Theo Arends & Christian Baars
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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.
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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.
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
--------------------------------------------------------------------------------------------
|
|
|
|
Version Date Action Description
|
|
|
|
--------------------------------------------------------------------------------------------
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
1.0.0.1 20190917 changed - rework of the inner loop to enable delays in the middle of I2C-reads
|
2019-09-29 12:27:50 +01:00
|
|
|
changed - double send address change only for fw>0x25
|
2019-09-18 19:57:35 +01:00
|
|
|
changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS
|
2019-09-29 12:27:50 +01:00
|
|
|
changed - do not publish missing temperature reads, show fw-version as hex
|
|
|
|
added - now really support the (slower) CHIRP!-Sensor
|
2019-09-18 19:57:35 +01:00
|
|
|
---
|
|
|
|
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
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
*/
|
2019-09-18 19:57:35 +01:00
|
|
|
|
|
|
|
#ifdef USE_I2C
|
|
|
|
#ifdef USE_CHIRP
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-29 12:27:50 +01:00
|
|
|
* CHIRP - Chirp!-sensor and I2C-soil-moisture-sensor
|
|
|
|
* !! The I2C-soil-moisture-sensor is the preferred one !!
|
2019-09-18 19:57:35 +01:00
|
|
|
*
|
|
|
|
* I2C Address: 0x20 - standard address, is changeable
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#define XSNS_48 48
|
|
|
|
#define CHIRP_MAX_SENSOR_COUNT 3 // 127 is expectectd to be the max number
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#define CHIRP_ADDR_STANDARD 0x20 // standard address
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* constants
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#define D_CMND_CHIRP "CHIRP"
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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";
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
const char kChirpTypes[] PROGMEM = "CHIRP";
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* enumerations
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* command defines
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#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
|
2019-09-29 12:27:50 +01:00
|
|
|
#define CHIRP_GET_VERSION 0x07 // 8 bit, read, -> 0x22 means 2.2
|
2019-09-18 19:57:35 +01:00
|
|
|
#define CHIRP_SLEEP 0x08 // no value, write
|
|
|
|
#define CHIRP_GET_BUSY 0x09 // 8 bit, read, -> 1 = busy, 0 = otherwise
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* helper function
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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;
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
// globals
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
uint8_t chirp_current = 0; // current selected/active sensor
|
|
|
|
uint8_t chirp_found_sensors = 0; // number of found sensors
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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)
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#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 ;)
|
2019-08-06 20:48:55 +01:00
|
|
|
};
|
2019-09-18 19:57:35 +01:00
|
|
|
#pragma pack()
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
ChirpSensor_t chirp_sensor[CHIRP_MAX_SENSOR_COUNT]; // should be 8 bytes per sensor slot
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpReset(uint8_t addr) {
|
|
|
|
ChirpWriteI2CRegister(addr, CHIRP_RESET);
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpResetAll(void) {
|
|
|
|
for (uint32_t i = 0; i < chirp_found_sensors; i++) {
|
|
|
|
if (chirp_sensor[i].version) {
|
|
|
|
ChirpReset(chirp_sensor[i].address);
|
|
|
|
}
|
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpClockSet() { // set I2C for this slow sensor
|
|
|
|
Wire.setClockStretchLimit(4000);
|
|
|
|
Wire.setClock(50000);
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpSleep(uint8_t addr) {
|
|
|
|
ChirpWriteI2CRegister(addr, CHIRP_SLEEP);
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
// void ChirpSleepAll(void) {
|
|
|
|
// for (uint32_t i = 0; i < chirp_found_sensors; i++) {
|
|
|
|
// if (chirp_sensor[i].version) {
|
|
|
|
// ChirpSleep(chirp_sensor[i].address);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
// /********************************************************************************************/
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
// 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);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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);
|
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
2019-09-29 12:27:50 +01:00
|
|
|
/******************************************************************************************************************/
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
uint8_t ChirpReadVersion(uint8_t addr) {
|
2019-09-29 12:27:50 +01:00
|
|
|
return (I2cRead8(addr, CHIRP_GET_VERSION)); // the Chirp!-sensor does not provide fw-version and we will get 255
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
2019-09-29 12:27:50 +01:00
|
|
|
/******************************************************************************************************************/
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
bool ChirpSet(uint8_t addr) {
|
|
|
|
if(addr < 128){
|
|
|
|
if (I2cWrite8(chirp_sensor[chirp_current].address, CHIRP_SET_ADDRESS, addr)){
|
2019-09-29 12:27:50 +01:00
|
|
|
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
|
|
|
|
}
|
2019-09-18 19:57:35 +01:00
|
|
|
DEBUG_SENSOR_LOG(PSTR("CHIRP: Wrote adress %u "), addr);
|
|
|
|
ChirpReset(chirp_sensor[chirp_current].address);
|
|
|
|
chirp_sensor[chirp_current].address = addr;
|
2019-09-29 12:27:50 +01:00
|
|
|
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"
|
|
|
|
}
|
2019-09-18 19:57:35 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2019-09-29 12:27:50 +01:00
|
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: address %u incorrect and not used"), addr);
|
2019-09-18 19:57:35 +01:00
|
|
|
return false;
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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<CHIRP_MAX_SENSOR_COUNT){
|
|
|
|
chirp_sensor[chirp_found_sensors].address = address; // push next sensor, as long as there is space in the array
|
2019-09-29 12:27:50 +01:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CHIRP: fw %x"), chirp_sensor[chirp_found_sensors].version);
|
2019-09-18 19:57:35 +01:00
|
|
|
}
|
|
|
|
chirp_found_sensors++;
|
|
|
|
}
|
|
|
|
}
|
2019-09-29 12:27:50 +01:00
|
|
|
// chirp_timeout_count = 11; // wait a second to read the real fw-version in the next step
|
2019-09-18 19:57:35 +01:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("Found %u CHIRP sensor(s)."), chirp_found_sensors);
|
|
|
|
if (chirp_found_sensors == 0) {return false;}
|
|
|
|
else {return true;}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpDetect(void)
|
2019-08-06 20:48:55 +01:00
|
|
|
{
|
2019-09-18 19:57:35 +01:00
|
|
|
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);
|
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
2019-09-17 21:03:30 +01:00
|
|
|
/********************************************************************************************/
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-09-17 21:03:30 +01:00
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpEvery100MSecond(void)
|
2019-08-06 20:48:55 +01:00
|
|
|
{
|
2019-09-18 19:57:35 +01:00
|
|
|
// 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
|
2019-09-29 12:27:50 +01:00
|
|
|
DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %u, tele: %u"), chirp_timeout_count, Settings.tele_period);
|
2019-09-18 19:57:35 +01:00
|
|
|
}
|
|
|
|
else{
|
|
|
|
AddLog_P2(LOG_LEVEL_INFO, PSTR("CHIRP: TELEPERIOD must be > 16 seconds !"));
|
2019-09-29 12:27:50 +01:00
|
|
|
// we could overwrite it to i.e. 20 seconds here
|
2019-09-18 19:57:35 +01:00
|
|
|
}
|
|
|
|
chirp_next_job = 1; // back to step 1
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
chirp_timeout_count--; // count down
|
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
2019-09-18 19:57:35 +01:00
|
|
|
// normaly in i18n.h
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#define D_JSON_MOISTURE "Moisture"
|
|
|
|
#define D_JSON_DARKNESS "Darkness"
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#ifdef USE_WEBSERVER
|
|
|
|
// {s} = <tr><th>, {m} = </th><td>, {e} = </td></tr>
|
2019-08-06 20:48:55 +01:00
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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
|
2019-08-06 20:48:55 +01:00
|
|
|
|
|
|
|
|
|
|
|
/********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
void ChirpShow(bool json)
|
2019-08-06 20:48:55 +01:00
|
|
|
{
|
2019-09-18 19:57:35 +01:00
|
|
|
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);
|
2019-09-29 12:27:50 +01:00
|
|
|
char str_light[33];
|
2019-09-18 19:57:35 +01:00
|
|
|
dtostrfd(chirp_sensor[i].light, 0, str_light);
|
2019-09-29 12:27:50 +01:00
|
|
|
char str_version[7];
|
2019-09-29 17:35:02 +01:00
|
|
|
if(chirp_sensor[i].version == 0xff){
|
2019-09-29 12:27:50 +01:00
|
|
|
strncpy_P(str_version, PSTR("Chirp!"), sizeof(str_version));
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
sprintf(str_version, "%x", chirp_sensor[i].version);
|
|
|
|
}
|
2019-09-18 19:57:35 +01:00
|
|
|
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);
|
|
|
|
}
|
2019-09-18 20:06:14 +01:00
|
|
|
ResponseAppend_P(PSTR(",\"" D_JSON_DARKNESS "\":%s}"),str_light);
|
2019-09-18 19:57:35 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
ResponseAppend_P(PSTR(",\"%s%u\":{\"sleeping\"}"),chirp_name, i);
|
|
|
|
}
|
|
|
|
#ifdef USE_DOMOTICZ
|
|
|
|
if (0 == tele_period) {
|
|
|
|
DomoticzTempHumSensor(str_temperature, str_moisture);
|
2019-09-29 12:27:50 +01:00
|
|
|
DomoticzSensor(DZ_ILLUMINANCE,chirp_sensor[i].light); // this is not LUX!!
|
2019-09-18 19:57:35 +01:00
|
|
|
}
|
|
|
|
#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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* check the Chirp commands
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
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);
|
|
|
|
|
|
|
|
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;
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************************************\
|
2019-09-18 19:57:35 +01:00
|
|
|
* Interface
|
2019-08-06 20:48:55 +01:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
bool Xsns48(uint8_t function)
|
2019-08-06 20:48:55 +01:00
|
|
|
{
|
2019-09-18 19:57:35 +01:00
|
|
|
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;
|
2019-08-06 20:48:55 +01:00
|
|
|
}
|
|
|
|
|
2019-09-18 19:57:35 +01:00
|
|
|
#endif // USE_CHIRP
|
|
|
|
#endif // USE_I2C
|