Merge branch 'development' into teleinfo

This commit is contained in:
Charles 2020-06-15 10:22:44 +02:00 committed by GitHub
commit ae9e770950
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 4759 additions and 1306 deletions

View File

@ -72,4 +72,5 @@ Index | Define | Driver | Device | Address(es) | Description
48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor 48 | USE_AS3935 | xsns_67 | AS3935 | 0x03 | Franklin Lightning Sensor
49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor 49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor 50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity sensor
51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor 51 | USE_MCP9808 | xsns_72 | MCP9808 | 0x18 - 0x1F | Temperature sensor
52 | USE_HP303B | xsns_73 | HP303B | 0x76 - 0x77 | Pressure and temperature sensor

View File

@ -52,7 +52,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
## Changelog ## Changelog
### Version 8.3.1.2 ### Version 8.3.1.3
- Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff - Created Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff
- Added Library to be used for decoding Teleinfo (French Metering Smart Meter) - Added Library to be used for decoding Teleinfo (French Metering Smart Meter)
@ -78,3 +78,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
- Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139) - Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139)
- Add support for up to eight MCP9808 temperature sensors by device111 (#8594) - Add support for up to eight MCP9808 temperature sensors by device111 (#8594)
- Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175) - Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175)
- Add initial support for Telegram bot (#8619)
- Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638)
- Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet

View File

@ -0,0 +1,4 @@
# Arduino library for the HP303B
### Installation
- Clone this repository or download&unzip [zip file](https://github.com/wemos/LOLIN_HP303B_Library/archive/master.zip) into Arduino/libraries

View File

@ -0,0 +1,98 @@
#include <LOLIN_HP303B.h>
// HP303B Opject
LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B();
void setup()
{
Serial.begin(115200);
while (!Serial);
//Call begin to initialize HP303BPressureSensor
//The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
//HP303BPressureSensor.begin(Wire, 0x76);
//Use the commented line below instead to use the default I2C address.
HP303BPressureSensor.begin();
//temperature measure rate (value from 0 to 7)
//2^temp_mr temperature measurement results per second
int16_t temp_mr = 2;
//temperature oversampling rate (value from 0 to 7)
//2^temp_osr internal temperature measurements per result
//A higher value increases precision
int16_t temp_osr = 2;
//pressure measure rate (value from 0 to 7)
//2^prs_mr pressure measurement results per second
int16_t prs_mr = 2;
//pressure oversampling rate (value from 0 to 7)
//2^prs_osr internal pressure measurements per result
//A higher value increases precision
int16_t prs_osr = 2;
//startMeasureBothCont enables background mode
//temperature and pressure ar measured automatically
//High precision and hgh measure rates at the same time are not available.
//Consult Datasheet (or trial and error) for more information
int16_t ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr);
//Use one of the commented lines below instead to measure only temperature or pressure
//int16_t ret = HP303BPressureSensor.startMeasureTempCont(temp_mr, temp_osr);
//int16_t ret = HP303BPressureSensor.startMeasurePressureCont(prs_mr, prs_osr);
if (ret != 0)
{
Serial.print("Init FAILED! ret = ");
Serial.println(ret);
}
else
{
Serial.println("Init complete!");
}
}
void loop()
{
unsigned char pressureCount = 20;
int32_t pressure[pressureCount];
unsigned char temperatureCount = 20;
int32_t temperature[temperatureCount];
//This function writes the results of continuous measurements to the arrays given as parameters
//The parameters temperatureCount and pressureCount should hold the sizes of the arrays temperature and pressure when the function is called
//After the end of the function, temperatureCount and pressureCount hold the numbers of values written to the arrays
//Note: The HP303B cannot save more than 32 results. When its result buffer is full, it won't save any new measurement results
int16_t ret = HP303BPressureSensor.getContResults(temperature, temperatureCount, pressure, pressureCount);
if (ret != 0)
{
Serial.println();
Serial.println();
Serial.print("FAIL! ret = ");
Serial.println(ret);
}
else
{
Serial.println();
Serial.println();
Serial.print(temperatureCount);
Serial.println(" temperature values found: ");
for (int16_t i = 0; i < temperatureCount; i++)
{
Serial.print(temperature[i]);
Serial.println(" degrees of Celsius");
}
Serial.println();
Serial.print(pressureCount);
Serial.println(" pressure values found: ");
for (int16_t i = 0; i < pressureCount; i++)
{
Serial.print(pressure[i]);
Serial.println(" Pascal");
}
}
//Wait some time, so that the HP303B can refill its buffer
delay(10000);
}

View File

@ -0,0 +1,75 @@
#include <LOLIN_HP303B.h>
// HP303B Opject
LOLIN_HP303B HP303BPressureSensor;
void setup()
{
Serial.begin(115200);
while (!Serial);
//Call begin to initialize HP303BPressureSensor
//The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
//HP303BPressureSensor.begin(Wire, 0x76);
//Use the commented line below instead of the one above to use the default I2C address.
//if you are using the Pressure 3 click Board, you need 0x76
HP303BPressureSensor.begin();
Serial.println("Init complete!");
}
void loop()
{
int32_t temperature;
int32_t pressure;
int16_t oversampling = 7;
int16_t ret;
Serial.println();
//lets the HP303B perform a Single temperature measurement with the last (or standard) configuration
//The result will be written to the paramerter temperature
//ret = HP303BPressureSensor.measureTempOnce(temperature);
//the commented line below does exactly the same as the one above, but you can also config the precision
//oversampling can be a value from 0 to 7
//the HP303B will perform 2^oversampling internal temperature measurements and combine them to one result with higher precision
//measurements with higher precision take more time, consult datasheet for more information
ret = HP303BPressureSensor.measureTempOnce(temperature, oversampling);
if (ret != 0)
{
//Something went wrong.
//Look at the library code for more information about return codes
Serial.print("FAIL! ret = ");
Serial.println(ret);
}
else
{
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" degrees of Celsius");
}
//Pressure measurement behaves like temperature measurement
//ret = HP303BPressureSensor.measurePressureOnce(pressure);
ret = HP303BPressureSensor.measurePressureOnce(pressure, oversampling);
if (ret != 0)
{
//Something went wrong.
//Look at the library code for more information about return codes
Serial.print("FAIL! ret = ");
Serial.println(ret);
}
else
{
Serial.print("Pressure: ");
Serial.print(pressure);
Serial.println(" Pascal");
}
//Wait some time
delay(500);
}

View File

@ -0,0 +1,112 @@
#include <LOLIN_HP303B.h>
// HP303B Opject
LOLIN_HP303B HP303BPressureSensor = LOLIN_HP303B();
void onFifoFull();
const unsigned char pressureLength = 50;
unsigned char pressureCount = 0;
int32_t pressure[pressureLength];
unsigned char temperatureCount = 0;
const unsigned char temperatureLength = 50;
int32_t temperature[temperatureLength];
void setup()
{
Serial.begin(115200);
while (!Serial);
//Call begin to initialize HP303BPressureSensor
//The parameter 0x76 is the bus address. The default address is 0x77 and does not need to be given.
//HP303BPressureSensor.begin(Wire, 0x76);
//Use the commented line below instead to use the default I2C address.
HP303BPressureSensor.begin();
int16_t ret = HP303BPressureSensor.setInterruptPolarity(1);
ret = HP303BPressureSensor.setInterruptSources(1, 0, 0);
//clear interrupt flag by reading
HP303BPressureSensor.getIntStatusFifoFull();
//initialization of Interrupt for Controller unit
//SDO pin of HP303B has to be connected with interrupt pin
int16_t interruptPin = 3;
pinMode(interruptPin, INPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), onFifoFull, RISING);
//start of a continuous measurement just like before
int16_t temp_mr = 3;
int16_t temp_osr = 2;
int16_t prs_mr = 1;
int16_t prs_osr = 3;
ret = HP303BPressureSensor.startMeasureBothCont(temp_mr, temp_osr, prs_mr, prs_osr);
if (ret != 0)
{
Serial.print("Init FAILED! ret = ");
Serial.println(ret);
}
else
{
Serial.println("Init complete!");
}
}
void loop()
{
//do other stuff
Serial.println("loop running");
delay(500);
//if result arrays are full
//This could also be in the interrupt handler, but it would take too much time for a proper ISR
if (pressureCount == pressureLength && temperatureCount == temperatureLength)
{
//print results
Serial.println();
Serial.println();
Serial.print(temperatureCount);
Serial.println(" temperature values found: ");
for (int16_t i = 0; i < temperatureCount; i++)
{
Serial.print(temperature[i]);
Serial.println(" degrees of Celsius");
}
Serial.println();
Serial.print(pressureCount);
Serial.println(" pressure values found: ");
for (int16_t i = 0; i < pressureCount; i++)
{
Serial.print(pressure[i]);
Serial.println(" Pascal");
}
Serial.println();
Serial.println();
//reset result counters
pressureCount = 0;
temperatureCount = 0;
}
}
//interrupt handler
void onFifoFull()
{
//message for debugging
Serial.println("Interrupt handler called");
//clear interrupt flag by reading
HP303BPressureSensor.getIntStatusFifoFull();
//calculate the number of free indexes in the result arrays
unsigned char prs_freespace = pressureLength - pressureCount;
unsigned char temp_freespace = temperatureLength - temperatureCount;
//read the results from HP303B, new results will be added at the end of the arrays
HP303BPressureSensor.getContResults(&temperature[temperatureCount], temp_freespace, &pressure[pressureCount], prs_freespace);
//after reading the result counters are increased by the amount of new results
pressureCount += prs_freespace;
temperatureCount += temp_freespace;
}

View File

@ -0,0 +1,26 @@
#######################################
# Syntax Coloring Map For DHT12
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
DHT12 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
get KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################
cTemp LITERAL1
fTemp LITERAL1
humidity LITERAL1

View File

@ -0,0 +1,9 @@
name=LOLIN_HP303B
version=1.0.0
author=WEMOS.CC <support@wemos.cc>
maintainer=WEMOS.CC
sentence=Library for the <a href="https://www.wemos.cc">HP303B.</a>.
paragraph=LOLIN HP303B
category=Device Control
url=https://github.com/wemos/LOLIN_HP303B_Library
architectures=*

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
#ifndef __LOLIN_HP303B_H
#define __LOLIN_HP303B_H
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
#include <SPI.h>
#include "util/hp303b_consts.h"
class LOLIN_HP303B
{
public:
//constructor
LOLIN_HP303B(void);
//destructor
~LOLIN_HP303B(void);
//begin
uint8_t begin(TwoWire &bus, uint8_t slaveAddress);
uint8_t begin(uint8_t slaveAddress=HP303B__STD_SLAVE_ADDRESS);
uint8_t begin(SPIClass &bus, int32_t chipSelect);
uint8_t begin(SPIClass &bus, int32_t chipSelect, uint8_t threeWire);
//end
void end(void);
//general
uint8_t getProductId(void);
uint8_t getRevisionId(void);
//Idle Mode
int16_t standby(void);
//Command Mode
int16_t measureTempOnce(float &result);
int16_t measureTempOnce(float &result, uint8_t slaveAddress);
int16_t measureTempOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate);
int16_t startMeasureTempOnce(void);
int16_t startMeasureTempOnce(uint8_t oversamplingRate);
int16_t measurePressureOnce(float &result);
int16_t measurePressureOnce(float &result, uint8_t slaveAddress);
int16_t measurePressureOnce(float &result, uint8_t slaveAddress, uint8_t oversamplingRate);
int16_t startMeasurePressureOnce(void);
int16_t startMeasurePressureOnce(uint8_t oversamplingRate);
int16_t getSingleResult(float &result);
//Background Mode
int16_t startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate);
int16_t startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate);
int16_t startMeasureBothCont(uint8_t tempMr, uint8_t tempOsr, uint8_t prsMr, uint8_t prsOsr);
int16_t getContResults(float *tempBuffer, uint8_t &tempCount, float *prsBuffer, uint8_t &prsCount);
//Interrupt Control
int16_t setInterruptPolarity(uint8_t polarity);
int16_t setInterruptSources(uint8_t fifoFull, uint8_t tempReady, uint8_t prsReady);
int16_t getIntStatusFifoFull(void);
int16_t getIntStatusTempReady(void);
int16_t getIntStatusPrsReady(void);
//function to fix a hardware problem on some devices
int16_t correctTemp(void);
private:
//scaling factor table
static const int32_t scaling_facts[HP303B__NUM_OF_SCAL_FACTS];
//enum for operating mode
enum Mode
{
IDLE = 0x00,
CMD_PRS = 0x01,
CMD_TEMP = 0x02,
INVAL_OP_CMD_BOTH = 0x03, //invalid
INVAL_OP_CONT_NONE = 0x04, //invalid
CONT_PRS = 0x05,
CONT_TMP = 0x06,
CONT_BOTH = 0x07
};
Mode m_opMode;
//flags
uint8_t m_initFail;
uint8_t m_productID;
uint8_t m_revisionID;
//settings
uint8_t m_tempMr;
uint8_t m_tempOsr;
uint8_t m_prsMr;
uint8_t m_prsOsr;
uint8_t m_tempSensor;
//compensation coefficients
int32_t m_c0Half;
int32_t m_c1;
int32_t m_c00;
int32_t m_c10;
int32_t m_c01;
int32_t m_c11;
int32_t m_c20;
int32_t m_c21;
int32_t m_c30;
//last measured scaled temperature
//(necessary for pressure compensation)
double m_lastTempScal;
//bus specific
uint8_t m_SpiI2c; //0=SPI, 1=I2C
//used for I2C
TwoWire *m_i2cbus;
uint8_t m_slaveAddress;
//used for SPI
SPIClass *m_spibus;
int32_t m_chipSelect;
uint8_t m_threeWire;
//measurement
uint8_t init(void);
int16_t readcoeffs(void);
int16_t setOpMode(uint8_t background, uint8_t temperature, uint8_t pressure);
int16_t setOpMode(uint8_t opMode);
int16_t configTemp(uint8_t temp_mr, uint8_t temp_osr);
int16_t configPressure(uint8_t prs_mr, uint8_t prs_osr);
uint16_t calcBusyTime(uint16_t temp_rate, uint16_t temp_osr);
int16_t getTemp(float *result);
int16_t getPressure(float *result);
int16_t getFIFOvalue(float *value);
float calcTemp(float raw);
float calcPressure(float raw);
//bus specific
int16_t readByte(uint8_t regAddress);
int16_t readByteSPI(uint8_t regAddress);
int16_t readBlock(uint8_t regAddress, uint8_t length, uint8_t *buffer);
int16_t readBlockSPI(uint8_t regAddress, uint8_t length, uint8_t *readbuffer);
int16_t writeByte(uint8_t regAddress, uint8_t data);
int16_t writeByte(uint8_t regAddress, uint8_t data, uint8_t check);
int16_t writeByteSpi(uint8_t regAddress, uint8_t data, uint8_t check);
int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift);
int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift, uint8_t check);
int16_t readByteBitfield(uint8_t regAddress, uint8_t mask, uint8_t shift);
};
#endif

View File

@ -0,0 +1,258 @@
/**
*
*
*/
#ifndef __HP303B_CONSTS_H_
#define __HP303B_CONSTS_H_
//general Constants
#define HP303B__PROD_ID 0U
#define HP303B__STD_SLAVE_ADDRESS 0x77U
#define HP303B__SPI_WRITE_CMD 0x00U
#define HP303B__SPI_READ_CMD 0x80U
#define HP303B__SPI_RW_MASK 0x80U
#define HP303B__SPI_MAX_FREQ 100000U
#define HP303B__LSB 0x01U
#define HP303B__TEMP_STD_MR 2U
#define HP303B__TEMP_STD_OSR 3U
#define HP303B__PRS_STD_MR 2U
#define HP303B__PRS_STD_OSR 3U
#define HP303B__OSR_SE 3U
//we use 0.1 mS units for time calculations, so 10 units are one millisecond
#define HP303B__BUSYTIME_SCALING 10U
// DPS310 has 10 milliseconds of spare time for each synchronous measurement / per second for asynchronous measurements
// this is for error prevention on friday-afternoon-products :D
// you can set it to 0 if you dare, but there is no warranty that it will still work
#define HP303B__BUSYTIME_FAILSAFE 10U
#define HP303B__MAX_BUSYTIME ((1000U-HP303B__BUSYTIME_FAILSAFE)*HP303B__BUSYTIME_SCALING)
#define HP303B__NUM_OF_SCAL_FACTS 8
#define HP303B__SUCCEEDED 0
#define HP303B__FAIL_UNKNOWN -1
#define HP303B__FAIL_INIT_FAILED -2
#define HP303B__FAIL_TOOBUSY -3
#define HP303B__FAIL_UNFINISHED -4
//Constants for register manipulation
//SPI mode (3 or 4 wire)
#define HP303B__REG_ADR_SPI3W 0x09U
#define HP303B__REG_CONTENT_SPI3W 0x01U
//product id
#define HP303B__REG_INFO_PROD_ID HP303B__REG_ADR_PROD_ID, \
HP303B__REG_MASK_PROD_ID, \
HP303B__REG_SHIFT_PROD_ID
#define HP303B__REG_ADR_PROD_ID 0x0DU
#define HP303B__REG_MASK_PROD_ID 0x0FU
#define HP303B__REG_SHIFT_PROD_ID 0U
//revision id
#define HP303B__REG_INFO_REV_ID HP303B__REG_ADR_REV_ID, \
HP303B__REG_MASK_REV_ID, \
HP303B__REG_SHIFT_REV_ID
#define HP303B__REG_ADR_REV_ID 0x0DU
#define HP303B__REG_MASK_REV_ID 0xF0U
#define HP303B__REG_SHIFT_REV_ID 4U
//operating mode
#define HP303B__REG_INFO_OPMODE HP303B__REG_ADR_OPMODE, \
HP303B__REG_MASK_OPMODE, \
HP303B__REG_SHIFT_OPMODE
#define HP303B__REG_ADR_OPMODE 0x08U
#define HP303B__REG_MASK_OPMODE 0x07U
#define HP303B__REG_SHIFT_OPMODE 0U
//temperature measure rate
#define HP303B__REG_INFO_TEMP_MR HP303B__REG_ADR_TEMP_MR, \
HP303B__REG_MASK_TEMP_MR, \
HP303B__REG_SHIFT_TEMP_MR
#define HP303B__REG_ADR_TEMP_MR 0x07U
#define HP303B__REG_MASK_TEMP_MR 0x70U
#define HP303B__REG_SHIFT_TEMP_MR 4U
//temperature oversampling rate
#define HP303B__REG_INFO_TEMP_OSR HP303B__REG_ADR_TEMP_OSR, \
HP303B__REG_MASK_TEMP_OSR, \
HP303B__REG_SHIFT_TEMP_OSR
#define HP303B__REG_ADR_TEMP_OSR 0x07U
#define HP303B__REG_MASK_TEMP_OSR 0x07U
#define HP303B__REG_SHIFT_TEMP_OSR 0U
//temperature sensor
#define HP303B__REG_INFO_TEMP_SENSOR HP303B__REG_ADR_TEMP_SENSOR, \
HP303B__REG_MASK_TEMP_SENSOR, \
HP303B__REG_SHIFT_TEMP_SENSOR
#define HP303B__REG_ADR_TEMP_SENSOR 0x07U
#define HP303B__REG_MASK_TEMP_SENSOR 0x80U
#define HP303B__REG_SHIFT_TEMP_SENSOR 7U
//temperature sensor recommendation
#define HP303B__REG_INFO_TEMP_SENSORREC HP303B__REG_ADR_TEMP_SENSORREC, \
HP303B__REG_MASK_TEMP_SENSORREC, \
HP303B__REG_SHIFT_TEMP_SENSORREC
#define HP303B__REG_ADR_TEMP_SENSORREC 0x28U
#define HP303B__REG_MASK_TEMP_SENSORREC 0x80U
#define HP303B__REG_SHIFT_TEMP_SENSORREC 7U
//temperature shift enable (if temp_osr>3)
#define HP303B__REG_INFO_TEMP_SE HP303B__REG_ADR_TEMP_SE, \
HP303B__REG_MASK_TEMP_SE, \
HP303B__REG_SHIFT_TEMP_SE
#define HP303B__REG_ADR_TEMP_SE 0x09U
#define HP303B__REG_MASK_TEMP_SE 0x08U
#define HP303B__REG_SHIFT_TEMP_SE 3U
//pressure measure rate
#define HP303B__REG_INFO_PRS_MR HP303B__REG_ADR_PRS_MR, \
HP303B__REG_MASK_PRS_MR, \
HP303B__REG_SHIFT_PRS_MR
#define HP303B__REG_ADR_PRS_MR 0x06U
#define HP303B__REG_MASK_PRS_MR 0x70U
#define HP303B__REG_SHIFT_PRS_MR 4U
//pressure oversampling rate
#define HP303B__REG_INFO_PRS_OSR HP303B__REG_ADR_PRS_OSR, \
HP303B__REG_MASK_PRS_OSR, \
HP303B__REG_SHIFT_PRS_OSR
#define HP303B__REG_ADR_PRS_OSR 0x06U
#define HP303B__REG_MASK_PRS_OSR 0x07U
#define HP303B__REG_SHIFT_PRS_OSR 0U
//pressure shift enable (if prs_osr>3)
#define HP303B__REG_INFO_PRS_SE HP303B__REG_ADR_PRS_SE, \
HP303B__REG_MASK_PRS_SE, \
HP303B__REG_SHIFT_PRS_SE
#define HP303B__REG_ADR_PRS_SE 0x09U
#define HP303B__REG_MASK_PRS_SE 0x04U
#define HP303B__REG_SHIFT_PRS_SE 2U
//temperature ready flag
#define HP303B__REG_INFO_TEMP_RDY HP303B__REG_ADR_TEMP_RDY, \
HP303B__REG_MASK_TEMP_RDY, \
HP303B__REG_SHIFT_TEMP_RDY
#define HP303B__REG_ADR_TEMP_RDY 0x08U
#define HP303B__REG_MASK_TEMP_RDY 0x20U
#define HP303B__REG_SHIFT_TEMP_RDY 5U
//pressure ready flag
#define HP303B__REG_INFO_PRS_RDY HP303B__REG_ADR_PRS_RDY, \
HP303B__REG_MASK_PRS_RDY, \
HP303B__REG_SHIFT_PRS_RDY
#define HP303B__REG_ADR_PRS_RDY 0x08U
#define HP303B__REG_MASK_PRS_RDY 0x10U
#define HP303B__REG_SHIFT_PRS_RDY 4U
//pressure value
#define HP303B__REG_ADR_PRS 0x00U
#define HP303B__REG_LEN_PRS 3U
//temperature value
#define HP303B__REG_ADR_TEMP 0x03U
#define HP303B__REG_LEN_TEMP 3U
//compensation coefficients
#define HP303B__REG_ADR_COEF 0x10U
#define HP303B__REG_LEN_COEF 18
//FIFO enable
#define HP303B__REG_INFO_FIFO_EN HP303B__REG_ADR_FIFO_EN, \
HP303B__REG_MASK_FIFO_EN, \
HP303B__REG_SHIFT_FIFO_EN
#define HP303B__REG_ADR_FIFO_EN 0x09U
#define HP303B__REG_MASK_FIFO_EN 0x02U
#define HP303B__REG_SHIFT_FIFO_EN 1U
//FIFO flush
#define HP303B__REG_INFO_FIFO_FL HP303B__REG_ADR_FIFO_EN, \
HP303B__REG_MASK_FIFO_EN, \
HP303B__REG_SHIFT_FIFO_EN
#define HP303B__REG_ADR_FIFO_FL 0x0CU
#define HP303B__REG_MASK_FIFO_FL 0x80U
#define HP303B__REG_SHIFT_FIFO_FL 7U
//FIFO empty
#define HP303B__REG_INFO_FIFO_EMPTY HP303B__REG_ADR_FIFO_EMPTY, \
HP303B__REG_MASK_FIFO_EMPTY, \
HP303B__REG_SHIFT_FIFO_EMPTY
#define HP303B__REG_ADR_FIFO_EMPTY 0x0BU
#define HP303B__REG_MASK_FIFO_EMPTY 0x01U
#define HP303B__REG_SHIFT_FIFO_EMPTY 0U
//FIFO full
#define HP303B__REG_INFO_FIFO_FULL HP303B__REG_ADR_FIFO_FULL, \
HP303B__REG_MASK_FIFO_FULL, \
HP303B__REG_SHIFT_FIFO_FULL
#define HP303B__REG_ADR_FIFO_FULL 0x0BU
#define HP303B__REG_MASK_FIFO_FULL 0x02U
#define HP303B__REG_SHIFT_FIFO_FULL 1U
//INT HL
#define HP303B__REG_INFO_INT_HL HP303B__REG_ADR_INT_HL, \
HP303B__REG_MASK_INT_HL, \
HP303B__REG_SHIFT_INT_HL
#define HP303B__REG_ADR_INT_HL 0x09U
#define HP303B__REG_MASK_INT_HL 0x80U
#define HP303B__REG_SHIFT_INT_HL 7U
//INT FIFO enable
#define HP303B__REG_INFO_INT_EN_FIFO HP303B__REG_ADR_INT_EN_FIFO, \
HP303B__REG_MASK_INT_EN_FIFO, \
HP303B__REG_SHIFT_INT_EN_FIFO
#define HP303B__REG_ADR_INT_EN_FIFO 0x09U
#define HP303B__REG_MASK_INT_EN_FIFO 0x40U
#define HP303B__REG_SHIFT_INT_EN_FIFO 6U
//INT TEMP enable
#define HP303B__REG_INFO_INT_EN_TEMP HP303B__REG_ADR_INT_EN_TEMP, \
HP303B__REG_MASK_INT_EN_TEMP, \
HP303B__REG_SHIFT_INT_EN_TEMP
#define HP303B__REG_ADR_INT_EN_TEMP 0x09U
#define HP303B__REG_MASK_INT_EN_TEMP 0x20U
#define HP303B__REG_SHIFT_INT_EN_TEMP 5U
//INT PRS enable
#define HP303B__REG_INFO_INT_EN_PRS HP303B__REG_ADR_INT_EN_PRS, \
HP303B__REG_MASK_INT_EN_PRS, \
HP303B__REG_SHIFT_INT_EN_PRS
#define HP303B__REG_ADR_INT_EN_PRS 0x09U
#define HP303B__REG_MASK_INT_EN_PRS 0x10U
#define HP303B__REG_SHIFT_INT_EN_PRS 4U
//INT FIFO flag
#define HP303B__REG_INFO_INT_FLAG_FIFO HP303B__REG_ADR_INT_FLAG_FIFO, \
HP303B__REG_MASK_INT_FLAG_FIFO, \
HP303B__REG_SHIFT_INT_FLAG_FIFO
#define HP303B__REG_ADR_INT_FLAG_FIFO 0x0AU
#define HP303B__REG_MASK_INT_FLAG_FIFO 0x04U
#define HP303B__REG_SHIFT_INT_FLAG_FIFO 2U
//INT TMP flag
#define HP303B__REG_INFO_INT_FLAG_TEMP HP303B__REG_ADR_INT_FLAG_TEMP, \
HP303B__REG_MASK_INT_FLAG_TEMP, \
HP303B__REG_SHIFT_INT_FLAG_TEMP
#define HP303B__REG_ADR_INT_FLAG_TEMP 0x0AU
#define HP303B__REG_MASK_INT_FLAG_TEMP 0x02U
#define HP303B__REG_SHIFT_INT_FLAG_TEMP 1U
//INT PRS flag
#define HP303B__REG_INFO_INT_FLAG_PRS HP303B__REG_ADR_INT_FLAG_PRS, \
HP303B__REG_MASK_INT_FLAG_PRS, \
HP303B__REG_SHIFT_INT_FLAG_PRS
#define HP303B__REG_ADR_INT_FLAG_PRS 0x0AU
#define HP303B__REG_MASK_INT_FLAG_PRS 0x01U
#define HP303B__REG_SHIFT_INT_FLAG_PRS 0U
#endif /* DPS310_CONSTS_H_ */

View File

@ -128,6 +128,6 @@ build_flags = ${tasmota_core.build_flags}
[tasmota_core] [tasmota_core]
; *** Esp8266 Arduino core 2.7.1 ; *** Esp8266 Arduino core 2.7.1
platform = espressif8266@2.5.1 platform = espressif8266@2.5.2
platform_packages = platform_packages =
build_flags = ${esp82xx_defaults.build_flags} build_flags = ${esp82xx_defaults.build_flags}

View File

@ -1,5 +1,11 @@
## Unreleased (development) ## Unreleased (development)
### 8.3.1.3 20200611
- Add initial support for Telegram bot (#8619)
- Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638)
- Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet
### 8.3.1.2 20200522 ### 8.3.1.2 20200522
- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]``

View File

@ -40,7 +40,7 @@ uint32_t *stack_thunk_light_save = NULL; /* Saved A1 while in BearSSL */
uint32_t stack_thunk_light_refcnt = 0; uint32_t stack_thunk_light_refcnt = 0;
//#define _stackSize (5600/4) //#define _stackSize (5600/4)
#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER) #ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
#define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes #define _stackSize (5300/4) // using a light version of bearssl we can save 300 bytes
#else #else
#define _stackSize (3600/4) // using a light version of bearssl we can save 2k #define _stackSize (3600/4) // using a light version of bearssl we can save 2k

View File

@ -52,7 +52,7 @@ extern uint32_t stack_thunk_light_refcnt;
// Thunking macro // Thunking macro
#define make_stack_thunk_light(fcnToThunk) \ #define make_stack_thunk_light(fcnToThunk) \
__asm("\n\ __asm__("\n\
.text\n\ .text\n\
.literal_position\n\ .literal_position\n\
.literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\ .literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\

1827
tasmota/WiFiClientSecureLightBearSSL.cpp Normal file → Executable file

File diff suppressed because it is too large Load Diff

442
tasmota/WiFiClientSecureLightBearSSL.h Normal file → Executable file
View File

@ -1,221 +1,221 @@
/* /*
WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries WiFiClientBearSSL- SSL client/server for esp8266 using BearSSL libraries
- Mostly compatible with Arduino WiFi shield library and standard - Mostly compatible with Arduino WiFi shield library and standard
WiFiClient/ServerSecure (except for certificate handling). WiFiClient/ServerSecure (except for certificate handling).
Copyright (c) 2018 Earle F. Philhower, III Copyright (c) 2018 Earle F. Philhower, III
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, This library 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 GNU MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include <core_version.h> #include <core_version.h>
#ifndef wificlientlightbearssl_h #ifndef wificlientlightbearssl_h
#define wificlientlightbearssl_h #define wificlientlightbearssl_h
#if defined(USE_MQTT_TLS) || defined (USE_SENDMAIL) #ifdef USE_TLS
#include <vector> #include <vector>
#include "WiFiClient.h" #include "WiFiClient.h"
#include <t_bearssl.h> #include <t_bearssl.h>
namespace BearSSL { namespace BearSSL {
class WiFiClientSecure_light : public WiFiClient { class WiFiClientSecure_light : public WiFiClient {
public: public:
WiFiClientSecure_light(int recv, int xmit); WiFiClientSecure_light(int recv, int xmit);
~WiFiClientSecure_light() override; ~WiFiClientSecure_light() override;
void allocateBuffers(void); void allocateBuffers(void);
int connect(IPAddress ip, uint16_t port) override; int connect(IPAddress ip, uint16_t port) override;
int connect(const char* name, uint16_t port) override; int connect(const char* name, uint16_t port) override;
uint8_t connected() override; uint8_t connected() override;
size_t write(const uint8_t *buf, size_t size) override; size_t write(const uint8_t *buf, size_t size) override;
size_t write_P(PGM_P buf, size_t size) override; size_t write_P(PGM_P buf, size_t size) override;
size_t write(const char *buf) { size_t write(const char *buf) {
return write((const uint8_t*)buf, strlen(buf)); return write((const uint8_t*)buf, strlen(buf));
} }
size_t write_P(const char *buf) { size_t write_P(const char *buf) {
return write_P((PGM_P)buf, strlen_P(buf)); return write_P((PGM_P)buf, strlen_P(buf));
} }
size_t write(Stream& stream); // Note this is not virtual size_t write(Stream& stream); // Note this is not virtual
int read(uint8_t *buf, size_t size) override; int read(uint8_t *buf, size_t size) override;
int available() override; int available() override;
int read() override; int read() override;
int peek() override; int peek() override;
size_t peekBytes(uint8_t *buffer, size_t length) override; size_t peekBytes(uint8_t *buffer, size_t length) override;
bool flush(unsigned int maxWaitMs); bool flush(unsigned int maxWaitMs);
bool stop(unsigned int maxWaitMs); bool stop(unsigned int maxWaitMs);
void flush() override { (void)flush(0); } void flush() override { (void)flush(0); }
void stop() override { (void)stop(0); } void stop() override { (void)stop(0); }
// Only check SHA1 fingerprint of public key // Only check SHA1 fingerprint of public key
void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2, void setPubKeyFingerprint(const uint8_t *f1, const uint8_t *f2,
bool f_any = false) { bool f_any = false) {
_fingerprint1 = f1; _fingerprint1 = f1;
_fingerprint2 = f2; _fingerprint2 = f2;
_fingerprint_any = f_any; _fingerprint_any = f_any;
} }
const uint8_t * getRecvPubKeyFingerprint(void) { const uint8_t * getRecvPubKeyFingerprint(void) {
return _recv_fingerprint; return _recv_fingerprint;
} }
void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk, void setClientECCert(const br_x509_certificate *cert, const br_ec_private_key *sk,
unsigned allowed_usages, unsigned cert_issuer_key_type); unsigned allowed_usages, unsigned cert_issuer_key_type);
void setTrustAnchor(const br_x509_trust_anchor *ta); void setTrustAnchor(const br_x509_trust_anchor *ta);
// Sets the requested buffer size for transmit and receive // Sets the requested buffer size for transmit and receive
void setBufferSizes(int recv, int xmit); void setBufferSizes(int recv, int xmit);
// Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection) // Returns whether MFLN negotiation for the above buffer sizes succeeded (after connection)
int getMFLNStatus() { int getMFLNStatus() {
return connected() && br_ssl_engine_get_mfln_negotiated(_eng); return connected() && br_ssl_engine_get_mfln_negotiated(_eng);
} }
int32_t getLastError(void) { int32_t getLastError(void) {
if (_last_error) { if (_last_error) {
return _last_error; return _last_error;
} else { } else {
return br_ssl_engine_last_error(_eng); return br_ssl_engine_last_error(_eng);
} }
} }
inline void setLastError(int32_t err) { inline void setLastError(int32_t err) {
_last_error = err; _last_error = err;
} }
inline void clearLastError(void) { inline void clearLastError(void) {
_last_error = 0; _last_error = 0;
} }
inline size_t getMaxThunkStackUse(void) { inline size_t getMaxThunkStackUse(void) {
return _max_thunkstack_use; return _max_thunkstack_use;
} }
private: private:
void _clear(); void _clear();
bool _ctx_present; bool _ctx_present;
std::shared_ptr<br_ssl_client_context> _sc; std::shared_ptr<br_ssl_client_context> _sc;
inline bool ctx_present() { inline bool ctx_present() {
return _ctx_present; return _ctx_present;
} }
br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts br_ssl_engine_context *_eng; // &_sc->eng, to allow for client or server contexts
std::shared_ptr<unsigned char> _iobuf_in; std::shared_ptr<unsigned char> _iobuf_in;
std::shared_ptr<unsigned char> _iobuf_out; std::shared_ptr<unsigned char> _iobuf_out;
time_t _now; time_t _now;
int _iobuf_in_size; int _iobuf_in_size;
int _iobuf_out_size; int _iobuf_out_size;
bool _handshake_done; bool _handshake_done;
uint64_t _last_error; uint64_t _last_error;
bool _fingerprint_any; // accept all fingerprints bool _fingerprint_any; // accept all fingerprints
const uint8_t *_fingerprint1; // fingerprint1 to be checked against const uint8_t *_fingerprint1; // fingerprint1 to be checked against
const uint8_t *_fingerprint2; // fingerprint2 to be checked against const uint8_t *_fingerprint2; // fingerprint2 to be checked against
uint8_t _recv_fingerprint[20]; // fingerprint received uint8_t _recv_fingerprint[20]; // fingerprint received
unsigned char *_recvapp_buf; unsigned char *_recvapp_buf;
size_t _recvapp_len; size_t _recvapp_len;
bool _clientConnected(); // Is the underlying socket alive? bool _clientConnected(); // Is the underlying socket alive?
bool _connectSSL(const char *hostName); // Do initial SSL handshake bool _connectSSL(const char *hostName); // Do initial SSL handshake
void _freeSSL(); void _freeSSL();
int _run_until(unsigned target, bool blocking = true); int _run_until(unsigned target, bool blocking = true);
size_t _write(const uint8_t *buf, size_t size, bool pmem); size_t _write(const uint8_t *buf, size_t size, bool pmem);
bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting bool _wait_for_handshake(); // Sets and return the _handshake_done after connecting
// Optional client certificate // Optional client certificate
const br_x509_certificate *_chain_P; // PROGMEM certificate const br_x509_certificate *_chain_P; // PROGMEM certificate
const br_ec_private_key *_sk_ec_P; // PROGMEM private key const br_ec_private_key *_sk_ec_P; // PROGMEM private key
const br_x509_trust_anchor *_ta_P; // PROGMEM server CA const br_x509_trust_anchor *_ta_P; // PROGMEM server CA
unsigned _allowed_usages; unsigned _allowed_usages;
unsigned _cert_issuer_key_type; unsigned _cert_issuer_key_type;
// record the maximum use of ThunkStack for monitoring // record the maximum use of ThunkStack for monitoring
size_t _max_thunkstack_use; size_t _max_thunkstack_use;
}; };
#define ERR_OOM -1000 #define ERR_OOM -1000
#define ERR_CANT_RESOLVE_IP -1001 #define ERR_CANT_RESOLVE_IP -1001
#define ERR_TCP_CONNECT -1002 #define ERR_TCP_CONNECT -1002
#define ERR_MISSING_EC_KEY -1003 // #define ERR_MISSING_EC_KEY -1003 // deprecated, AWS IoT is not called if the private key is not present
#define ERR_MISSING_CA -1004 #define ERR_MISSING_CA -1004
// For reference, BearSSL error codes: // For reference, BearSSL error codes:
// #define BR_ERR_OK 0 // #define BR_ERR_OK 0
// #define BR_ERR_BAD_PARAM 1 // #define BR_ERR_BAD_PARAM 1
// #define BR_ERR_BAD_STATE 2 // #define BR_ERR_BAD_STATE 2
// #define BR_ERR_UNSUPPORTED_VERSION 3 // #define BR_ERR_UNSUPPORTED_VERSION 3
// #define BR_ERR_BAD_VERSION 4 // #define BR_ERR_BAD_VERSION 4
// #define BR_ERR_BAD_LENGTH 5 // #define BR_ERR_BAD_LENGTH 5
// #define BR_ERR_TOO_LARGE 6 // #define BR_ERR_TOO_LARGE 6
// #define BR_ERR_BAD_MAC 7 // #define BR_ERR_BAD_MAC 7
// #define BR_ERR_NO_RANDOM 8 // #define BR_ERR_NO_RANDOM 8
// #define BR_ERR_UNKNOWN_TYPE 9 // #define BR_ERR_UNKNOWN_TYPE 9
// #define BR_ERR_UNEXPECTED 10 // #define BR_ERR_UNEXPECTED 10
// #define BR_ERR_BAD_CCS 12 // #define BR_ERR_BAD_CCS 12
// #define BR_ERR_BAD_ALERT 13 // #define BR_ERR_BAD_ALERT 13
// #define BR_ERR_BAD_HANDSHAKE 14 // #define BR_ERR_BAD_HANDSHAKE 14
// #define BR_ERR_OVERSIZED_ID 15 // #define BR_ERR_OVERSIZED_ID 15
// #define BR_ERR_BAD_CIPHER_SUITE 16 // #define BR_ERR_BAD_CIPHER_SUITE 16
// #define BR_ERR_BAD_COMPRESSION 17 // #define BR_ERR_BAD_COMPRESSION 17
// #define BR_ERR_BAD_FRAGLEN 18 // #define BR_ERR_BAD_FRAGLEN 18
// #define BR_ERR_BAD_SECRENEG 19 // #define BR_ERR_BAD_SECRENEG 19
// #define BR_ERR_EXTRA_EXTENSION 20 // #define BR_ERR_EXTRA_EXTENSION 20
// #define BR_ERR_BAD_SNI 21 // #define BR_ERR_BAD_SNI 21
// #define BR_ERR_BAD_HELLO_DONE 22 // #define BR_ERR_BAD_HELLO_DONE 22
// #define BR_ERR_LIMIT_EXCEEDED 23 // #define BR_ERR_LIMIT_EXCEEDED 23
// #define BR_ERR_BAD_FINISHED 24 // #define BR_ERR_BAD_FINISHED 24
// #define BR_ERR_RESUME_MISMATCH 25 // #define BR_ERR_RESUME_MISMATCH 25
// #define BR_ERR_INVALID_ALGORITHM 26 // #define BR_ERR_INVALID_ALGORITHM 26
// #define BR_ERR_BAD_SIGNATURE 27 // #define BR_ERR_BAD_SIGNATURE 27
// #define BR_ERR_WRONG_KEY_USAGE 28 // #define BR_ERR_WRONG_KEY_USAGE 28
// #define BR_ERR_NO_CLIENT_AUTH 29 // #define BR_ERR_NO_CLIENT_AUTH 29
// #define BR_ERR_IO 31 // #define BR_ERR_IO 31
// #define BR_ERR_RECV_FATAL_ALERT 256 // #define BR_ERR_RECV_FATAL_ALERT 256
// #define BR_ERR_SEND_FATAL_ALERT 512 // #define BR_ERR_SEND_FATAL_ALERT 512
// #define BR_ERR_X509_OK 32 // #define BR_ERR_X509_OK 32
// #define BR_ERR_X509_INVALID_VALUE 33 // #define BR_ERR_X509_INVALID_VALUE 33
// #define BR_ERR_X509_TRUNCATED 34 // #define BR_ERR_X509_TRUNCATED 34
// #define BR_ERR_X509_EMPTY_CHAIN 35 // #define BR_ERR_X509_EMPTY_CHAIN 35
// #define BR_ERR_X509_INNER_TRUNC 36 // #define BR_ERR_X509_INNER_TRUNC 36
// #define BR_ERR_X509_BAD_TAG_CLASS 37 // #define BR_ERR_X509_BAD_TAG_CLASS 37
// #define BR_ERR_X509_BAD_TAG_VALUE 38 // #define BR_ERR_X509_BAD_TAG_VALUE 38
// #define BR_ERR_X509_INDEFINITE_LENGTH 39 // #define BR_ERR_X509_INDEFINITE_LENGTH 39
// #define BR_ERR_X509_EXTRA_ELEMENT 40 // #define BR_ERR_X509_EXTRA_ELEMENT 40
// #define BR_ERR_X509_UNEXPECTED 41 // #define BR_ERR_X509_UNEXPECTED 41
// #define BR_ERR_X509_NOT_CONSTRUCTED 42 // #define BR_ERR_X509_NOT_CONSTRUCTED 42
// #define BR_ERR_X509_NOT_PRIMITIVE 43 // #define BR_ERR_X509_NOT_PRIMITIVE 43
// #define BR_ERR_X509_PARTIAL_BYTE 44 // #define BR_ERR_X509_PARTIAL_BYTE 44
// #define BR_ERR_X509_BAD_BOOLEAN 45 // #define BR_ERR_X509_BAD_BOOLEAN 45
// #define BR_ERR_X509_OVERFLOW 46 // #define BR_ERR_X509_OVERFLOW 46
// #define BR_ERR_X509_BAD_DN 47 // #define BR_ERR_X509_BAD_DN 47
// #define BR_ERR_X509_BAD_TIME 48 // #define BR_ERR_X509_BAD_TIME 48
// #define BR_ERR_X509_UNSUPPORTED 49 // #define BR_ERR_X509_UNSUPPORTED 49
// #define BR_ERR_X509_LIMIT_EXCEEDED 50 // #define BR_ERR_X509_LIMIT_EXCEEDED 50
// #define BR_ERR_X509_WRONG_KEY_TYPE 51 // #define BR_ERR_X509_WRONG_KEY_TYPE 51
// #define BR_ERR_X509_BAD_SIGNATURE 52 // #define BR_ERR_X509_BAD_SIGNATURE 52
// #define BR_ERR_X509_TIME_UNKNOWN 53 // #define BR_ERR_X509_TIME_UNKNOWN 53
// #define BR_ERR_X509_EXPIRED 54 // #define BR_ERR_X509_EXPIRED 54
// #define BR_ERR_X509_DN_MISMATCH 55 // #define BR_ERR_X509_DN_MISMATCH 55
// #define BR_ERR_X509_BAD_SERVER_NAME 56 // #define BR_ERR_X509_BAD_SERVER_NAME 56
// #define BR_ERR_X509_CRITICAL_EXTENSION 57 // #define BR_ERR_X509_CRITICAL_EXTENSION 57
// #define BR_ERR_X509_NOT_CA 58 // #define BR_ERR_X509_NOT_CA 58
// #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59 // #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
// #define BR_ERR_X509_WEAK_PUBLIC_KEY 60 // #define BR_ERR_X509_WEAK_PUBLIC_KEY 60
// #define BR_ERR_X509_NOT_TRUSTED 62 // #define BR_ERR_X509_NOT_TRUSTED 62
}; };
#endif // USE_MQTT_TLS #endif // USE_TLS
#endif // wificlientlightbearssl_h #endif // wificlientlightbearssl_h

View File

@ -672,7 +672,7 @@
#define D_SENSOR_HM10_TX "HM10 - TX" #define D_SENSOR_HM10_TX "HM10 - TX"
#define D_SENSOR_LE01MR_RX "LE-01MR - RX" #define D_SENSOR_LE01MR_RX "LE-01MR - RX"
#define D_SENSOR_LE01MR_TX "LE-01MR - TX" #define D_SENSOR_LE01MR_TX "LE-01MR - TX"
#define D_SENSOR_BL0940_RX "BL0940 Rx" #define D_SENSOR_BL0940_RX "BL0940 - Rx"
#define D_SENSOR_CC1101_GDO0 "CC1101 - GDO0" #define D_SENSOR_CC1101_GDO0 "CC1101 - GDO0"
#define D_SENSOR_CC1101_GDO2 "CC1101 - GDO2" #define D_SENSOR_CC1101_GDO2 "CC1101 - GDO2"
#define D_SENSOR_HRXL_RX "HRXL - RX" #define D_SENSOR_HRXL_RX "HRXL - RX"

View File

@ -367,6 +367,11 @@
// Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT // Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT
// #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048 // #define USE_4K_RSA // Support 4096 bits certificates, instead of 2048
// -- Telegram Protocol ---------------------------
//#define USE_TELEGRAM // Support for Telegram protocol (+49k code, +7.0k mem and +4.8k additional during connection handshake)
#define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
// #define USE_MQTT_TLS_CA_CERT // Use certificate instead of fingerprint
// -- KNX IP Protocol ----------------------------- // -- KNX IP Protocol -----------------------------
//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) //#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem)
#define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem) #define USE_KNX_WEB_MENU // Enable KNX WEB MENU (+8.3k code, +144 mem)
@ -522,6 +527,7 @@
// #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code) // #define USE_VEML6075 // [I2cDriver49] Enable VEML6075 UVA/UVB/UVINDEX Sensor (I2C address 0x10) (+2k1 code)
// #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code) // #define USE_VEML7700 // [I2cDriver50] Enable VEML7700 Ambient Light sensor (I2C addresses 0x10) (+4k5 code)
// #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code) // #define USE_MCP9808 // [I2cDriver51] Enable MCP9808 temperature sensor (I2C addresses 0x18 - 0x1F) (+0k9 code)
// #define USE_HP303B // [I2cDriver52] Enable HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
// #define USE_DISPLAY // Add I2C Display Support (+2k code) // #define USE_DISPLAY // Add I2C Display Support (+2k code)
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
@ -755,4 +761,16 @@
#error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time" #error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time"
#endif #endif
/*********************************************************************************************\
* Post-process compile options for TLS
\*********************************************************************************************/
#if defined(USE_MQTT_TLS) || defined(USE_SENDMAIL) || defined(USE_TELEGRAM)
#define USE_TLS // flag indicates we need to include TLS code
#if defined(USE_MQTT_AWS_IOT) || defined(USE_TELEGRAM)
#define USE_MQTT_TLS_FORCE_EC_CIPHER // AWS IoT and TELEGRAM require EC Cipher
#endif
#endif
#endif // _MY_USER_CONFIG_H_ #endif // _MY_USER_CONFIG_H_

View File

@ -647,13 +647,14 @@ struct XDRVMAILBOX {
} XdrvMailbox; } XdrvMailbox;
#ifdef USE_SHUTTER #ifdef USE_SHUTTER
const uint8_t MAX_RULES_FLAG = 10; // Number of bits used in RulesBitfield (tricky I know...) const uint8_t MAX_RULES_FLAG = 11; // Number of bits used in RulesBitfield (tricky I know...)
#else #else
const uint8_t MAX_RULES_FLAG = 8; // Number of bits used in RulesBitfield (tricky I know...) const uint8_t MAX_RULES_FLAG = 9; // Number of bits used in RulesBitfield (tricky I know...)
#endif // USE_SHUTTER #endif // USE_SHUTTER
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful... typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint16_t data; // Allow bit manipulation uint16_t data; // Allow bit manipulation
struct { struct {
uint16_t system_init : 1; // Changing layout here needs adjustments in xdrv_10_rules.ino too
uint16_t system_boot : 1; uint16_t system_boot : 1;
uint16_t time_init : 1; uint16_t time_init : 1;
uint16_t time_set : 1; uint16_t time_set : 1;
@ -664,7 +665,6 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint16_t http_init : 1; uint16_t http_init : 1;
uint16_t shutter_moved : 1; uint16_t shutter_moved : 1;
uint16_t shutter_moving : 1; uint16_t shutter_moving : 1;
uint16_t spare10 : 1;
uint16_t spare11 : 1; uint16_t spare11 : 1;
uint16_t spare12 : 1; uint16_t spare12 : 1;
uint16_t spare13 : 1; uint16_t spare13 : 1;

View File

@ -167,6 +167,8 @@ float CharToFloat(const char *str)
float right = 0; float right = 0;
if (*pt == '.') { if (*pt == '.') {
pt++; pt++;
// limit decimals to float max
pt[7]=0;
right = atoi(pt); // Decimal part right = atoi(pt); // Decimal part
while (isdigit(*pt)) { while (isdigit(*pt)) {
pt++; pt++;
@ -687,9 +689,9 @@ void ResetGlobalValues(void)
{ {
if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
global_update = 0; global_update = 0;
global_temperature = 9999; global_temperature = NAN;
global_humidity = 0; global_humidity = 0.0f;
global_pressure = 0; global_pressure = 0.0f;
} }
} }
@ -997,7 +999,7 @@ char* ResponseGetTime(uint32_t format, char* time_str)
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime());
break; break;
case 3: case 3:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s.%03d\""), GetDateAndTime(DT_LOCAL).c_str(), RtcMillis()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL_MILLIS).c_str());
break; break;
default: default:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
@ -1908,4 +1910,4 @@ String Decompress(const char * compressed, size_t uncompressed_size) {
return content; return content;
} }
#endif // USE_UNISHOX_COMPRESSION #endif // USE_UNISHOX_COMPRESSION

View File

@ -626,7 +626,7 @@ void CmndGlobalTemp(void)
if (!isnan(temperature) && Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit if (!isnan(temperature) && Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit
temperature = (temperature - 32) / 1.8; // Celsius temperature = (temperature - 32) / 1.8; // Celsius
} }
if ((temperature >= -50.0) && (temperature <= 100.0)) { if ((temperature >= -50.0f) && (temperature <= 100.0f)) {
ConvertTemp(temperature); ConvertTemp(temperature);
global_update = 1; // Keep global values just entered valid global_update = 1; // Keep global values just entered valid
} }

View File

@ -575,11 +575,16 @@ void GetFeatures(void)
#ifdef USE_BL0940 #ifdef USE_BL0940
feature6 |= 0x00004000; // xnrg_14_bl0940.ino feature6 |= 0x00004000; // xnrg_14_bl0940.ino
#endif #endif
#ifdef USE_TELEGRAM
feature6 |= 0x00008000; // xdrv_40_telegram.ino
#endif
#ifdef USE_HP303B
feature6 |= 0x00010000; // xsns_73_hp303b.ino
#endif
#ifdef USE_TELEINFO #ifdef USE_TELEINFO
feature6 |= 0x00008000; // xnrg_15_teleinfo.ino feature6 |= 0x00020000; // xnrg_15_teleinfo.ino
#endif #endif
// feature6 |= 0x00010000;
// feature6 |= 0x00020000; // feature6 |= 0x00020000;
// feature6 |= 0x00040000; // feature6 |= 0x00040000;
// feature6 |= 0x00080000; // feature6 |= 0x00080000;

View File

@ -206,6 +206,14 @@ String GetDateAndTime(uint8_t time_type)
break; break;
} }
String dt = GetDT(time); // 2017-03-07T11:08:02 String dt = GetDT(time); // 2017-03-07T11:08:02
if (DT_LOCAL_MILLIS == time_type) {
char ms[10];
snprintf_P(ms, sizeof(ms), PSTR(".%03d"), RtcMillis());
dt += ms;
time_type = DT_LOCAL;
}
if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { // SetOption52 - Append timezone to JSON time if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { // SetOption52 - Append timezone to JSON time
dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00 dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00
} }

View File

@ -214,7 +214,7 @@ enum WeekInMonthOptions {Last, First, Second, Third, Fourth};
enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat}; enum DayOfTheWeekOptions {Sun=1, Mon, Tue, Wed, Thu, Fri, Sat};
enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec}; enum MonthNamesOptions {Jan=1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec};
enum HemisphereOptions {North, South}; enum HemisphereOptions {North, South};
enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT }; enum GetDateAndTimeOptions { DT_LOCAL, DT_UTC, DT_LOCALNOTZ, DT_DST, DT_STD, DT_RESTART, DT_ENERGY, DT_BOOTCOUNT, DT_LOCAL_MILLIS };
enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE}; enum LoggingLevels {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE};
@ -293,7 +293,7 @@ enum SettingsTextIndex { SET_OTAURL,
SET_TEMPLATE_NAME, SET_TEMPLATE_NAME,
SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4, SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
SET_DEVICENAME, SET_DEVICENAME,
SET_TELEGRAMTOKEN, SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID,
SET_MAX }; SET_MAX };
enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND }; enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND };
@ -321,9 +321,10 @@ enum DevGroupShareItem { DGR_SHARE_POWER = 1, DGR_SHARE_LIGHT_BRI = 2, DGR_SHARE
enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER, enum CommandSource { SRC_IGNORE, SRC_MQTT, SRC_RESTART, SRC_BUTTON, SRC_SWITCH, SRC_BACKLOG, SRC_SERIAL, SRC_WEBGUI, SRC_WEBCOMMAND, SRC_WEBCONSOLE, SRC_PULSETIMER,
SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER, SRC_TIMER, SRC_RULE, SRC_MAXPOWER, SRC_MAXENERGY, SRC_OVERTEMP, SRC_LIGHT, SRC_KNX, SRC_DISPLAY, SRC_WEMO, SRC_HUE, SRC_RETRY, SRC_REMOTE, SRC_SHUTTER,
SRC_THERMOSTAT, SRC_MAX }; SRC_THERMOSTAT, SRC_CHAT, SRC_MAX };
const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|" const char kCommandSource[] PROGMEM = "I|MQTT|Restart|Button|Switch|Backlog|Serial|WebGui|WebCommand|WebConsole|PulseTimer|"
"Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|Thermostat"; "Timer|Rule|MaxPower|MaxEnergy|Overtemp|Light|Knx|Display|Wemo|Hue|Retry|Remote|Shutter|"
"Thermostat|Chat";
const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 }; const uint8_t kDefaultRfCode[9] PROGMEM = { 0x21, 0x16, 0x01, 0x0E, 0x03, 0x48, 0x2E, 0x1A, 0x00 };
@ -344,10 +345,10 @@ const SerConfu8 kTasmotaSerialConfig[] PROGMEM = {
SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2 SERIAL_5O2, SERIAL_6O2, SERIAL_7O2, SERIAL_8O2
}; };
enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4, enum TuyaSupportedFunctions { TUYA_MCU_FUNC_NONE, TUYA_MCU_FUNC_SWT1 = 1, TUYA_MCU_FUNC_SWT2, TUYA_MCU_FUNC_SWT3, TUYA_MCU_FUNC_SWT4,
TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5, TUYA_MCU_FUNC_REL1 = 11, TUYA_MCU_FUNC_REL2, TUYA_MCU_FUNC_REL3, TUYA_MCU_FUNC_REL4, TUYA_MCU_FUNC_REL5,
TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31, TUYA_MCU_FUNC_REL6, TUYA_MCU_FUNC_REL7, TUYA_MCU_FUNC_REL8, TUYA_MCU_FUNC_DIMMER = 21, TUYA_MCU_FUNC_POWER = 31,
TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE, TUYA_MCU_FUNC_CURRENT, TUYA_MCU_FUNC_VOLTAGE, TUYA_MCU_FUNC_BATTERY_STATE, TUYA_MCU_FUNC_BATTERY_PERCENTAGE,
TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV, TUYA_MCU_FUNC_REL1_INV = 41, TUYA_MCU_FUNC_REL2_INV, TUYA_MCU_FUNC_REL3_INV, TUYA_MCU_FUNC_REL4_INV, TUYA_MCU_FUNC_REL5_INV,
TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255 TUYA_MCU_FUNC_REL6_INV, TUYA_MCU_FUNC_REL7_INV, TUYA_MCU_FUNC_REL8_INV, TUYA_MCU_FUNC_LOWPOWER_MODE = 51, TUYA_MCU_FUNC_LAST = 255
}; };

View File

@ -36,9 +36,9 @@
#include "tasmota_version.h" // Tasmota version information #include "tasmota_version.h" // Tasmota version information
#include "tasmota.h" // Enumeration used in my_user_config.h #include "tasmota.h" // Enumeration used in my_user_config.h
#include "my_user_config.h" // Fixed user configurable options #include "my_user_config.h" // Fixed user configurable options
#ifdef USE_MQTT_TLS #ifdef USE_TLS
#include <t_bearssl.h> // We need to include before "tasmota_globals.h" to take precedence over the BearSSL version in Arduino #include <t_bearssl.h> // We need to include before "tasmota_globals.h" to take precedence over the BearSSL version in Arduino
#endif // USE_MQTT_TLS #endif // USE_TLS
#include "tasmota_globals.h" // Function prototypes and global configuration #include "tasmota_globals.h" // Function prototypes and global configuration
#include "i18n.h" // Language support configured by my_user_config.h #include "i18n.h" // Language support configured by my_user_config.h
#include "tasmota_template.h" // Hardware configuration #include "tasmota_template.h" // Hardware configuration
@ -111,9 +111,9 @@ uint32_t uptime = 0; // Counting every second until 42949
uint32_t loop_load_avg = 0; // Indicative loop load average uint32_t loop_load_avg = 0; // Indicative loop load average
uint32_t global_update = 0; // Timestamp of last global temperature and humidity update uint32_t global_update = 0; // Timestamp of last global temperature and humidity update
uint32_t web_log_index = 1; // Index in Web log buffer (should never be 0) uint32_t web_log_index = 1; // Index in Web log buffer (should never be 0)
float global_temperature = 9999; // Provide a global temperature to be used by some sensors float global_temperature = NAN; // Provide a global temperature to be used by some sensors
float global_humidity = 0; // Provide a global humidity to be used by some sensors float global_humidity = 0.0f; // Provide a global humidity to be used by some sensors
float global_pressure = 0; // Provide a global pressure to be used by some sensors float global_pressure = 0.0f; // Provide a global pressure to be used by some sensors
uint16_t tele_period = 9999; // Tele period timer uint16_t tele_period = 9999; // Tele period timer
uint16_t blink_counter = 0; // Number of blink cycles uint16_t blink_counter = 0; // Number of blink cycles
uint16_t seriallog_timer = 0; // Timer to disable Seriallog uint16_t seriallog_timer = 0; // Timer to disable Seriallog
@ -322,6 +322,8 @@ void setup(void) {
XdrvCall(FUNC_INIT); XdrvCall(FUNC_INIT);
XsnsCall(FUNC_INIT); XsnsCall(FUNC_INIT);
rules_flag.system_init = 1;
} }
void BacklogLoop(void) { void BacklogLoop(void) {

View File

@ -21,9 +21,8 @@
// Please use fingerprint validation instead // Please use fingerprint validation instead
// However, the CA are available below for future use if it appears to be useful // However, the CA are available below for future use if it appears to be useful
#ifdef USE_MQTT_TLS_CA_CERT #if defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)
#ifndef USE_MQTT_AWS_IOT
/*********************************************************************************************\ /*********************************************************************************************\
* LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417 * LetsEncrypt IdenTrust DST Root CA X3 certificate, RSA 2048 bits SHA 256, valid until 20210417
* *
@ -35,7 +34,7 @@
* remove "static" and add "PROGMEM" * remove "static" and add "PROGMEM"
\*********************************************************************************************/ \*********************************************************************************************/
static const unsigned char PROGMEM TA0_DN[] = { static const unsigned char PROGMEM LetsEncrypt_DN[] = {
0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x30, 0x4A, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72, 0x13, 0x0D, 0x4C, 0x65, 0x74, 0x27, 0x73, 0x20, 0x45, 0x6E, 0x63, 0x72,
@ -45,7 +44,7 @@ static const unsigned char PROGMEM TA0_DN[] = {
0x79, 0x20, 0x58, 0x33 0x79, 0x20, 0x58, 0x33
}; };
static const unsigned char PROGMEM TA0_RSA_N[] = { static const unsigned char PROGMEM LetsEncrypt_RSA_N[] = {
0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37, 0x9C, 0xD3, 0x0C, 0xF0, 0x5A, 0xE5, 0x2E, 0x47, 0xB7, 0x72, 0x5D, 0x37,
0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1, 0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1,
0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05, 0xBD, 0xBE, 0x35, 0xF1, 0x70, 0x92, 0x2F, 0xB7, 0xB8, 0x4B, 0x41, 0x05,
@ -70,27 +69,22 @@ static const unsigned char PROGMEM TA0_RSA_N[] = {
0xD8, 0x7D, 0xC3, 0x93 0xD8, 0x7D, 0xC3, 0x93
}; };
static const unsigned char TA0_RSA_E[] = { static const unsigned char LetsEncrypt_RSA_E[] = {
0x01, 0x00, 0x01 0x01, 0x00, 0x01
}; };
static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = { static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
{ (unsigned char *)TA0_DN, sizeof TA0_DN }, { (unsigned char *)LetsEncrypt_DN, sizeof LetsEncrypt_DN },
BR_X509_TA_CA, BR_X509_TA_CA,
{ {
BR_KEYTYPE_RSA, BR_KEYTYPE_RSA,
{ .rsa = { { .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, (unsigned char *)LetsEncrypt_RSA_N, sizeof LetsEncrypt_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, (unsigned char *)LetsEncrypt_RSA_E, sizeof LetsEncrypt_RSA_E,
} } } }
} }
}; };
#define TAs_NUM 1
#endif // not USE_MQTT_AWS_IOT
#ifdef USE_MQTT_AWS_IOT
/*********************************************************************************************\ /*********************************************************************************************\
* Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117 * Amazon Root CA, RSA 2048 bits SHA 256, valid until 20380117
* *
@ -103,7 +97,7 @@ static const br_x509_trust_anchor PROGMEM LetsEncryptX3CrossSigned_TA = {
\*********************************************************************************************/ \*********************************************************************************************/
const unsigned char PROGMEM TA0_DN[] = { const unsigned char PROGMEM AmazonRootCA1_DN[] = {
0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x30, 0x39, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A,
0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17, 0x13, 0x06, 0x41, 0x6D, 0x61, 0x7A, 0x6F, 0x6E, 0x31, 0x19, 0x30, 0x17,
@ -111,7 +105,7 @@ const unsigned char PROGMEM TA0_DN[] = {
0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31 0x6E, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x41, 0x20, 0x31
}; };
const unsigned char PROGMEM TA0_RSA_N[] = { const unsigned char PROGMEM AmazonRootCA1_RSA_N[] = {
0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80, 0xB2, 0x78, 0x80, 0x71, 0xCA, 0x78, 0xD5, 0xE3, 0x71, 0xAF, 0x47, 0x80,
0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7, 0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7,
0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86, 0x58, 0x21, 0x60, 0xF9, 0x74, 0x84, 0x01, 0x2F, 0xAC, 0x02, 0x2D, 0x86,
@ -136,24 +130,79 @@ const unsigned char PROGMEM TA0_RSA_N[] = {
0x9A, 0xC8, 0xAA, 0x0D 0x9A, 0xC8, 0xAA, 0x0D
}; };
static const unsigned char PROGMEM TA0_RSA_E[] = { static const unsigned char PROGMEM AmazonRootCA1_RSA_E[] = {
0x01, 0x00, 0x01 0x01, 0x00, 0x01
}; };
const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = { const br_x509_trust_anchor PROGMEM AmazonRootCA1_TA = {
{ (unsigned char *)TA0_DN, sizeof TA0_DN }, { (unsigned char *)AmazonRootCA1_DN, sizeof AmazonRootCA1_DN },
BR_X509_TA_CA, BR_X509_TA_CA,
{ {
BR_KEYTYPE_RSA, BR_KEYTYPE_RSA,
{ .rsa = { { .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N, (unsigned char *)AmazonRootCA1_RSA_N, sizeof AmazonRootCA1_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E, (unsigned char *)AmazonRootCA1_RSA_E, sizeof AmazonRootCA1_RSA_E,
} } } }
} }
}; };
#define TAs_NUM 1 // we add a separate CA for telegram
/*********************************************************************************************\
* GoDaddy Daddy Secure Certificate Authority - G2, RSA 2048 bits SHA 256, valid until 20220523
*
* to convert do: "brssl ta GoDaddyCA.pem"
* then copy and paste below, chain the generic names to the same as below
* remove "static" and add "PROGMEM"
\*********************************************************************************************/
#endif // USE_MQTT_AWS_IOT const unsigned char GoDaddyCAG2_DN[] PROGMEM = {
0x30, 0x3E, 0x31, 0x21, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x04, 0x0B, 0x13,
0x18, 0x44, 0x6F, 0x6D, 0x61, 0x69, 0x6E, 0x20, 0x43, 0x6F, 0x6E, 0x74,
0x72, 0x6F, 0x6C, 0x20, 0x56, 0x61, 0x6C, 0x69, 0x64, 0x61, 0x74, 0x65,
0x64, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x10,
0x61, 0x70, 0x69, 0x2E, 0x74, 0x65, 0x6C, 0x65, 0x67, 0x72, 0x61, 0x6D,
0x2E, 0x6F, 0x72, 0x67
};
#endif // USE_MQTT_TLS_CA_CERT const unsigned char GoDaddyCAG2_RSA_N[] PROGMEM = {
0xB4, 0xA3, 0x16, 0x9E, 0x5C, 0x57, 0xC9, 0x89, 0x65, 0xED, 0xEA, 0x78,
0x0B, 0xAE, 0x8A, 0x58, 0x2F, 0xAE, 0x5A, 0xC8, 0x6E, 0x49, 0x8D, 0xFC,
0x57, 0xA5, 0x98, 0x88, 0x78, 0x2E, 0x0B, 0x3C, 0x40, 0x3C, 0x21, 0x2E,
0x9A, 0x94, 0x98, 0x33, 0xA7, 0xE3, 0x42, 0xA7, 0x85, 0xFA, 0xD0, 0x73,
0x84, 0x01, 0x1C, 0x72, 0x39, 0x37, 0x23, 0xB5, 0x56, 0x1D, 0x43, 0xA5,
0x71, 0x14, 0x08, 0x24, 0xA5, 0x39, 0xCC, 0xDE, 0x58, 0x53, 0x94, 0x8E,
0x2A, 0x42, 0xA7, 0x4E, 0x2D, 0x07, 0x32, 0x9E, 0xBA, 0x8B, 0xD3, 0x2A,
0xA9, 0x9E, 0xC0, 0xE3, 0xCE, 0x9A, 0x10, 0x96, 0x45, 0x58, 0x7A, 0xC7,
0x1E, 0x45, 0x14, 0x23, 0x92, 0xBB, 0x54, 0x82, 0x88, 0x94, 0x49, 0xB6,
0xBE, 0x81, 0x21, 0x00, 0x29, 0x6D, 0xC9, 0xCE, 0x8B, 0x39, 0x3A, 0xDC,
0x35, 0x15, 0xD9, 0xEB, 0x47, 0x9C, 0xEF, 0xBA, 0x09, 0x0E, 0x16, 0xE4,
0xD9, 0xEB, 0x72, 0x30, 0xFA, 0x49, 0xAB, 0x98, 0x31, 0x7C, 0xB3, 0xAC,
0x2B, 0x29, 0x91, 0x87, 0x08, 0x41, 0x72, 0x5E, 0x35, 0xC7, 0x87, 0x04,
0x22, 0xF5, 0x48, 0x76, 0x30, 0x6D, 0x88, 0xDF, 0xF2, 0xA5, 0x29, 0x13,
0x70, 0xB3, 0x87, 0x02, 0xD5, 0x6B, 0x58, 0xB1, 0xE8, 0x73, 0xC7, 0xE4,
0xEF, 0x79, 0x86, 0xA4, 0x07, 0x5F, 0x67, 0xB4, 0x79, 0x8D, 0xA4, 0x25,
0x01, 0x82, 0x8C, 0xE0, 0x30, 0x17, 0xCB, 0x4B, 0x5C, 0xFB, 0xEB, 0x4C,
0x12, 0x51, 0xB9, 0xC9, 0x04, 0x1F, 0x7E, 0xD2, 0xF8, 0xBA, 0xF5, 0x35,
0x8D, 0x8A, 0x1C, 0x37, 0x82, 0xF0, 0x15, 0x73, 0x00, 0x6E, 0x3D, 0x1C,
0x76, 0x8B, 0x01, 0x74, 0x81, 0x3D, 0xE4, 0x2C, 0xA7, 0xCC, 0x2F, 0x66,
0xDC, 0x44, 0xA8, 0x27, 0x3F, 0xEA, 0xD0, 0xA7, 0xA8, 0xF1, 0xCB, 0xEA,
0xDA, 0x07, 0x38, 0xBD
};
const unsigned char GoDaddyCAG2_RSA_E[] PROGMEM = {
0x01, 0x00, 0x01
};
const br_x509_trust_anchor GoDaddyCAG2_TA PROGMEM = {
{ (unsigned char *)GoDaddyCAG2_DN, sizeof GoDaddyCAG2_DN },
0,
{
BR_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)GoDaddyCAG2_RSA_N, sizeof GoDaddyCAG2_RSA_N,
(unsigned char *)GoDaddyCAG2_RSA_E, sizeof GoDaddyCAG2_RSA_E,
} }
}
};
#endif // defined(USE_TLS) && defined(USE_MQTT_TLS_CA_CERT)

View File

@ -155,6 +155,7 @@
//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem) //#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code) //#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
//#define USE_MCP9808 // Add support for MCP9808 temperature sensor (+0k9 code) //#define USE_MCP9808 // Add support for MCP9808 temperature sensor (+0k9 code)
//#define USE_HP303B // Add support for HP303B temperature and pressure sensor (I2C address 0x76 or 0x77) (+6k2 code)
#define USE_ENERGY_SENSOR // Add energy sensors (-14k code) #define USE_ENERGY_SENSOR // Add energy sensors (-14k code)
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)

View File

@ -88,7 +88,7 @@ extern "C" void resetPins();
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
#endif #endif
#if defined(USE_MQTT_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0) #if defined(USE_TLS) && defined(ARDUINO_ESP8266_RELEASE_2_3_0)
#error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher." #error "TLS is no more supported on Core 2.3.0, use 2.4.2 or higher."
#endif #endif

View File

@ -20,7 +20,7 @@
#ifndef _TASMOTA_VERSION_H_ #ifndef _TASMOTA_VERSION_H_
#define _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_
const uint32_t VERSION = 0x08030102; const uint32_t VERSION = 0x08030103;
// Lowest compatible version // Lowest compatible version
const uint32_t VERSION_COMPATIBLE = 0x07010006; const uint32_t VERSION_COMPATIBLE = 0x07010006;

View File

@ -459,7 +459,12 @@ void EnergyEverySecond(void)
{ {
// Overtemp check // Overtemp check
if (global_update) { if (global_update) {
if (power && (global_temperature != 9999) && (global_temperature > Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays if (power && !isnan(global_temperature) && (global_temperature > (float)Settings.param[P_OVER_TEMP])) { // Device overtemp, turn off relays
char temperature[33];
dtostrfd(global_temperature, 1, temperature);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("NRG: GlobTemp %s"), temperature);
SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP); SetAllPower(POWER_ALL_OFF, SRC_OVERTEMP);
} }
} }
@ -1137,6 +1142,9 @@ bool Xdrv03(uint8_t function)
case FUNC_EVERY_250_MSECOND: case FUNC_EVERY_250_MSECOND:
XnrgCall(FUNC_EVERY_250_MSECOND); XnrgCall(FUNC_EVERY_250_MSECOND);
break; break;
case FUNC_EVERY_SECOND:
XnrgCall(FUNC_EVERY_SECOND);
break;
case FUNC_SERIAL: case FUNC_SERIAL:
result = XnrgCall(FUNC_SERIAL); result = XnrgCall(FUNC_SERIAL);
break; break;

View File

@ -1555,10 +1555,10 @@ void LightState(uint8_t append)
if (!Light.pwm_multi_channels) { if (!Light.pwm_multi_channels) {
if (unlinked) { if (unlinked) {
// RGB and W are unlinked, we display the second Power/Dimmer // RGB and W are unlinked, we display the second Power/Dimmer
ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d" ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "1\":%d"
",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"), ",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "2\":%d"),
Light.device, GetStateText(Light.power & 1), Light.device, light_state.getDimmer(1), Light.device, GetStateText(Light.power & 1), light_state.getDimmer(1),
Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), Light.device + 1, light_state.getDimmer(2)); Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), light_state.getDimmer(2));
} else { } else {
GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1 GetPowerDevice(scommand, Light.device, sizeof(scommand), Settings.flag.device_index_enable); // SetOption26 - Switch between POWER or POWER1
ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1), ResponseAppend_P(PSTR("\"%s\":\"%s\",\"" D_CMND_DIMMER "\":%d"), scommand, GetStateText(Light.power & 1),

View File

@ -887,17 +887,18 @@ void RulesEvery50ms(void)
rules_flag.data ^= mask; rules_flag.data ^= mask;
json_event[0] = '\0'; json_event[0] = '\0';
switch (i) { switch (i) {
case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break; case 0: strncpy_P(json_event, PSTR("{\"System\":{\"Init\":1}}"), sizeof(json_event)); break;
case 1: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break; case 1: strncpy_P(json_event, PSTR("{\"System\":{\"Boot\":1}}"), sizeof(json_event)); break;
case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break; case 2: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Initialized\":%d}}"), MinutesPastMidnight()); break;
case 3: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break; case 3: snprintf_P(json_event, sizeof(json_event), PSTR("{\"Time\":{\"Set\":%d}}"), MinutesPastMidnight()); break;
case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break; case 4: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 5: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break; case 5: strncpy_P(json_event, PSTR("{\"MQTT\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break; case 6: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Connected\":1}}"), sizeof(json_event)); break;
case 7: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break; case 7: strncpy_P(json_event, PSTR("{\"WIFI\":{\"Disconnected\":1}}"), sizeof(json_event)); break;
case 8: strncpy_P(json_event, PSTR("{\"HTTP\":{\"Initialized\":1}}"), sizeof(json_event)); break;
#ifdef USE_SHUTTER #ifdef USE_SHUTTER
case 8: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moved\":1}}"), sizeof(json_event)); break; case 9: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moved\":1}}"), sizeof(json_event)); break;
case 9: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moving\":1}}"), sizeof(json_event)); break; case 10: strncpy_P(json_event, PSTR("{\"SHUTTER\":{\"Moving\":1}}"), sizeof(json_event)); break;
#endif // USE_SHUTTER #endif // USE_SHUTTER
} }
if (json_event[0]) { if (json_event[0]) {

View File

@ -26,7 +26,6 @@ uses about 17 k of flash
to do to do
optimize code for space optimize code for space
g:var gloabal vars (via udp broadcast)
remarks remarks
@ -237,7 +236,11 @@ extern VButton *buttons[MAXBUTTONS];
#endif #endif
typedef union { typedef union {
#ifdef USE_SCRIPT_GLOBVARS
uint16_t data;
#else
uint8_t data; uint8_t data;
#endif
struct { struct {
uint8_t is_string : 1; // string or number uint8_t is_string : 1; // string or number
uint8_t is_permanent : 1; uint8_t is_permanent : 1;
@ -247,6 +250,9 @@ typedef union {
uint8_t settable : 1; uint8_t settable : 1;
uint8_t is_filter : 1; uint8_t is_filter : 1;
uint8_t constant : 1; uint8_t constant : 1;
#ifdef USE_SCRIPT_GLOBVARS
uint8_t global : 1;
#endif
}; };
} SCRIPT_TYPE; } SCRIPT_TYPE;
@ -276,6 +282,32 @@ typedef union {
}; };
} FILE_FLAGS; } FILE_FLAGS;
typedef union {
uint8_t data;
struct {
uint8_t nutu8 : 1;
uint8_t nutu7 : 1;
uint8_t nutu6 : 1;
uint8_t nutu5 : 1;
uint8_t nutu4 : 1;
uint8_t nutu3 : 1;
uint8_t udp_connected : 1;
uint8_t udp_used : 1;
};
} UDP_FLAGS;
#define NUM_RES 0xfe
#define STR_RES 0xfd
#define VAR_NV 0xff
#define NTYPE 0
#define STYPE 0x80
#ifndef FLT_MAX
#define FLT_MAX 99999999
#endif
#define SFS_MAX 4 #define SFS_MAX 4
// global memory // global memory
struct SCRIPT_MEM { struct SCRIPT_MEM {
@ -308,12 +340,19 @@ struct SCRIPT_MEM {
uint8_t script_sd_found; uint8_t script_sd_found;
char flink[2][14]; char flink[2][14];
#endif #endif
#ifdef USE_SCRIPT_GLOBVARS
UDP_FLAGS udp_flags;
#endif
} glob_script_mem; } glob_script_mem;
#ifdef USE_SCRIPT_GLOBVARS
IPAddress last_udp_ip;
#endif
int16_t last_findex; int16_t last_findex;
uint8_t tasm_cmd_activ=0; uint8_t tasm_cmd_activ=0;
uint8_t fast_script=0; uint8_t fast_script=0;
uint8_t glob_script=0;
uint32_t script_lastmillis; uint32_t script_lastmillis;
@ -436,6 +475,16 @@ char *script;
} else { } else {
vtypes[vars].bits.is_autoinc=0; vtypes[vars].bits.is_autoinc=0;
} }
#ifdef USE_SCRIPT_GLOBVARS
if (*lp=='g' && *(lp+1)==':') {
lp+=2;
vtypes[vars].bits.global=1;
glob_script_mem.udp_flags.udp_used = 1;
} else {
vtypes[vars].bits.global=0;
}
#endif
if ((*lp=='m' || *lp=='M') && *(lp+1)==':') { if ((*lp=='m' || *lp=='M') && *(lp+1)==':') {
uint8_t flg=*lp; uint8_t flg=*lp;
lp+=2; lp+=2;
@ -703,10 +752,112 @@ char *script;
// store start of actual program here // store start of actual program here
glob_script_mem.scriptptr=lp-1; glob_script_mem.scriptptr=lp-1;
glob_script_mem.scriptptr_bu=glob_script_mem.scriptptr; glob_script_mem.scriptptr_bu=glob_script_mem.scriptptr;
#ifdef USE_SCRIPT_GLOBVARS
if (glob_script_mem.udp_flags.udp_used) {
Script_Init_UDP();
glob_script=Run_Scripter(">G",-2,0);
}
#endif
return 0; return 0;
} }
#ifdef USE_SCRIPT_GLOBVARS
#define SCRIPT_UDP_BUFFER_SIZE 128
#define SCRIPT_UDP_PORT 1999
IPAddress script_udp_remote_ip;
void Script_Init_UDP() {
if (global_state.wifi_down) return;
if (glob_script_mem.udp_flags.udp_connected) return;
if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), SCRIPT_UDP_PORT)) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP "SCRIPT UDP started"));
glob_script_mem.udp_flags.udp_connected = 1;
} else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_UPNP "SCRIPT UDP failed"));
glob_script_mem.udp_flags.udp_connected = 0;
}
}
void Script_PollUdp(void) {
if (!glob_script_mem.udp_flags.udp_used) return;
if (glob_script_mem.udp_flags.udp_connected ) {
while (PortUdp.parsePacket()) {
char packet_buffer[SCRIPT_UDP_BUFFER_SIZE];
int32_t len = PortUdp.read(packet_buffer, SCRIPT_UDP_BUFFER_SIZE -1);
packet_buffer[len] = 0;
script_udp_remote_ip = PortUdp.remoteIP();
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("UDP: Packet %s - %d - %s"), packet_buffer, len, script_udp_remote_ip.toString().c_str());
char *lp=packet_buffer;
if (!strncmp(lp,"=>",2)) {
lp+=2;
char *cp=strchr(lp,'=');
if (cp) {
char vnam[32];
for (uint32_t count=0; count<len; count++) {
if (lp[count]=='=') {
vnam[count]=0;
break;
}
vnam[count]=lp[count];
}
float *fp;
char *sp;
uint32_t index;
uint32_t res=match_vars(vnam, &fp, &sp, &index);
if (res==NUM_RES) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("num var found - %s - %d"),vnam,res);
*fp=CharToFloat(cp+1);
} else if (res==STR_RES) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("string var found - %s - %d"),vnam,res);
strlcpy(sp,cp+1,SCRIPT_MAXSSIZE);
} else {
// error var not found
}
if (res) {
// mark changed
last_udp_ip=PortUdp.remoteIP();
glob_script_mem.type[index].bits.changed=1;
if (glob_script==99) {
Run_Scripter(">G",2,0);
}
}
}
}
optimistic_yield(100);
}
} else {
Script_Init_UDP();
}
}
void script_udp_sendvar(char *vname,float *fp,char *sp) {
if (!glob_script_mem.udp_flags.udp_used) return;
if (!glob_script_mem.udp_flags.udp_connected) return;
char sbuf[SCRIPT_MAXSSIZE+4];
strcpy(sbuf,"=>");
strcat(sbuf,vname);
strcat(sbuf,"=");
if (fp) {
char flstr[16];
dtostrfd(*fp,8,flstr);
strcat(sbuf,flstr);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("num var updated - %s"),sbuf);
} else {
strcat(sbuf,sp);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("string var updated - %s"),sbuf);
}
PortUdp.beginPacket(IPAddress(239,255,255,250), SCRIPT_UDP_PORT);
// Udp.print(String("RET UC: ") + String(recv_Packet));
PortUdp.write((const uint8_t*)sbuf,strlen(sbuf));
PortUdp.endPacket();
}
#endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
#ifdef USE_WS2812 #ifdef USE_WS2812
void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) { void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
@ -723,16 +874,7 @@ void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
#endif #endif
#endif #endif
#define NUM_RES 0xfe
#define STR_RES 0xfd
#define VAR_NV 0xff
#define NTYPE 0
#define STYPE 0x80
#ifndef FLT_MAX
#define FLT_MAX 99999999
#endif
float median_array(float *array,uint8_t len) { float median_array(float *array,uint8_t len) {
uint8_t ind[len]; uint8_t ind[len];
@ -1011,6 +1153,37 @@ uint32_t MeasurePulseTime(int32_t in) {
} }
#endif // USE_ANGLE_FUNC #endif // USE_ANGLE_FUNC
#ifdef USE_SCRIPT_GLOBVARS
uint32_t match_vars(char *dvnam, float **fp, char **sp, uint32_t *ind) {
uint16_t olen=strlen(dvnam);
struct T_INDEX *vtp=glob_script_mem.type;
for (uint32_t count=0; count<glob_script_mem.numvars; count++) {
char *cp=glob_script_mem.glob_vnp+glob_script_mem.vnp_offset[count];
uint8_t slen=strlen(cp);
if (slen==olen && *cp==dvnam[0]) {
if (!strncmp(cp,dvnam,olen)) {
uint8_t index=vtp[count].index;
if (vtp[count].bits.is_string==0) {
if (vtp[count].bits.is_filter) {
// error
return 0;
} else {
*fp=&glob_script_mem.fvars[index];
*ind=index;
return NUM_RES;
}
} else {
*sp=glob_script_mem.glob_snp+(index*glob_script_mem.max_ssize);
*ind=index;
return STR_RES;
}
}
}
}
return 0;
}
#endif
// vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number // vtype => ff=nothing found, fe=constant number,fd = constant string else bit 7 => 80 = string, 0 = number
// no flash strings here for performance reasons!!! // no flash strings here for performance reasons!!!
char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) { char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) {
@ -1765,12 +1938,40 @@ chknext:
len=0; len=0;
goto exit; goto exit;
} }
if (!strncmp(vname,"is(",3)) {
lp=GetNumericResult(lp+3,OPER_EQU,&fvar,0);
SCRIPT_SKIP_SPACES
if (*lp!='"') {
break;
}
lp++;
char *sstr=lp;
for (uint32_t cnt=0; cnt<256; cnt++) {
if (lp[cnt]='\n' || lp[cnt]=='"') {
lp+=cnt+1;
break;
}
}
char str[SCRIPT_MAXSSIZE];
GetTextIndexed(str, sizeof(str), fvar, sstr);
lp++;
if (sp) strlcpy(sp,str,glob_script_mem.max_ssize);
fvar=0;
len=0;
goto exit;
}
break; break;
case 'l': case 'l':
if (!strncmp(vname,"lip",3)) { if (!strncmp(vname,"lip",3)) {
if (sp) strlcpy(sp,(const char*)WiFi.localIP().toString().c_str(),glob_script_mem.max_ssize); if (sp) strlcpy(sp,(const char*)WiFi.localIP().toString().c_str(),glob_script_mem.max_ssize);
goto strexit; goto strexit;
} }
#ifdef USE_SCRIPT_GLOBVARS
if (!strncmp(vname,"luip",4)) {
if (sp) strlcpy(sp,IPAddressToString(last_udp_ip),glob_script_mem.max_ssize);
goto strexit;
}
#endif
if (!strncmp(vname,"loglvl",6)) { if (!strncmp(vname,"loglvl",6)) {
fvar=glob_script_mem.script_loglevel; fvar=glob_script_mem.script_loglevel;
tind->index=SCRIPT_LOGLEVEL; tind->index=SCRIPT_LOGLEVEL;
@ -3167,7 +3368,7 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line; if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line;
#ifdef IFTHEN_DEBUG #ifdef IFTHEN_DEBUG
sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]); sdtoff(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]);
toLogEOL(tbuff,lp); toLogEOL(tbuff,lp);
#endif #endif
@ -3382,8 +3583,16 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
} }
goto next_line; goto next_line;
} else { } else {
char *vnp=lp;
lp=isvar(lp,&vtype,&ind,&sysvar,0,0); lp=isvar(lp,&vtype,&ind,&sysvar,0,0);
if (vtype!=VAR_NV) { if (vtype!=VAR_NV) {
#ifdef USE_SCRIPT_GLOBVARS
char varname[16];
uint32_t vnl=(uint32_t)lp-(uint32)vnp;
strncpy(varname,vnp,vnl);
varname[vnl]=0;
#endif
// found variable as result // found variable as result
globvindex=ind.index; // save destination var index here globvindex=ind.index; // save destination var index here
globaindex=last_findex; globaindex=last_findex;
@ -3451,6 +3660,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
} }
// var was changed // var was changed
glob_script_mem.type[globvindex].bits.changed=1; glob_script_mem.type[globvindex].bits.changed=1;
#ifdef USE_SCRIPT_GLOBVARS
if (glob_script_mem.type[globvindex].bits.global) {
script_udp_sendvar(varname,dfvar,0);
}
#endif
if (glob_script_mem.type[globvindex].bits.is_filter) { if (glob_script_mem.type[globvindex].bits.is_filter) {
if (globaindex>=0) { if (globaindex>=0) {
Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar); Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar);
@ -3492,6 +3706,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!glob_script_mem.var_not_found) { if (!glob_script_mem.var_not_found) {
// var was changed // var was changed
glob_script_mem.type[globvindex].bits.changed=1; glob_script_mem.type[globvindex].bits.changed=1;
#ifdef USE_SCRIPT_GLOBVARS
if (glob_script_mem.type[globvindex].bits.global) {
script_udp_sendvar(varname,0,str);
}
#endif
if (lastop==OPER_EQU) { if (lastop==OPER_EQU) {
strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize); strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize);
} else if (lastop==OPER_PLSEQU) { } else if (lastop==OPER_PLSEQU) {
@ -3979,8 +4198,7 @@ void ListDir(char *path, uint8_t depth) {
char path[48]; char path[48];
void Script_FileUploadConfiguration(void) void Script_FileUploadConfiguration(void) {
{
uint8_t depth=0; uint8_t depth=0;
strcpy(path,"/"); strcpy(path,"/");
@ -3995,17 +4213,6 @@ void Script_FileUploadConfiguration(void)
} }
} }
void ScriptFileUploadSuccess(void) {
WSContentStart_P(S_INFORMATION);
WSContentSendStyle();
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br/>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(PSTR("</div><br/>"));
WSContentSend_P(PSTR("<p><form action='%s' method='get'><button>%s</button></form></p>"),"/upl",D_UPL_DONE);
//WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
WSContentStart_P(S_SCRIPT_FILE_UPLOAD); WSContentStart_P(S_SCRIPT_FILE_UPLOAD);
WSContentSendStyle(); WSContentSendStyle();
WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR); WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR);
@ -4023,13 +4230,22 @@ void Script_FileUploadConfiguration(void)
Web.upload_error = 0; Web.upload_error = 0;
} }
void ScriptFileUploadSuccess(void) {
WSContentStart_P(S_INFORMATION);
WSContentSendStyle();
WSContentSend_P(PSTR("<div style='text-align:center;'><b>" D_UPLOAD " <font color='#"));
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br/>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(PSTR("</div><br/>"));
WSContentSend_P(PSTR("<p><form action='%s' method='get'><button>%s</button></form></p>"),"/upl",D_UPL_DONE);
//WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
}
File upload_file; File upload_file;
void script_upload(void) { void script_upload(void) {
//AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload")); //AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload"));
HTTPUpload& upload = Webserver->upload(); HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) { if (upload.status == UPLOAD_FILE_START) {
char npath[48]; char npath[48];
@ -6139,6 +6355,12 @@ bool Xdrv10(uint8_t function)
break; break;
#endif #endif
#ifdef USE_SCRIPT_GLOBVARS
case FUNC_LOOP:
Script_PollUdp();
break;
#endif
} }
return result; return result;
} }

View File

@ -1331,7 +1331,7 @@ void ThermostatGetLocalSensor(uint8_t ctr_output) {
DynamicJsonBuffer jsonBuffer; DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data); JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data);
if (root.success()) { if (root.success()) {
const char* value_c = root["THERMOSTAT_SENSOR_NAME"]["Temperature"]; const char* value_c = root[THERMOSTAT_SENSOR_NAME]["Temperature"];
if (value_c != NULL && strlen(value_c) > 0 && (isdigit(value_c[0]) || (value_c[0] == '-' && isdigit(value_c[1])) ) ) { if (value_c != NULL && strlen(value_c) > 0 && (isdigit(value_c[0]) || (value_c[0] == '-' && isdigit(value_c[1])) ) ) {
int16_t value = (int16_t)(CharToFloat(value_c) * 10); int16_t value = (int16_t)(CharToFloat(value_c) * 10);
if ( (value >= -1000) if ( (value >= -1000)

View File

@ -0,0 +1,470 @@
/*
xdrv_40_telegram.ino - telegram for Tasmota
Copyright (C) 2020 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_TELEGRAM
/*********************************************************************************************\
* Telegram bot
*
* Supported commands:
* TmToken <token> - Add your BotFather created bot token (default none)
* TmChatId <chat_id> - Add your BotFather created bot chat id (default none)
* TmPoll <seconds> - Telegram receive poll time (default 10 seconds)
* TmState 0 - Disable telegram sending (default)
* TmState 1 - Enable telegram sending
* TmState 2 - Disable telegram listener (default)
* TmState 3 - Enable telegram listener
* TmState 4 - Disable telegram response echo (default)
* TmState 5 - Enable telegram response echo
* TmSend <data> - If telegram sending is enabled AND a chat id is present then send data
*
* Tested with defines
* #define USE_TELEGRAM // Support for Telegram protocol
* #define USE_TELEGRAM_FINGERPRINT "\xB2\x72\x47\xA6\x69\x8C\x3C\x69\xF9\x58\x6C\xF3\x60\x02\xFB\x83\xFA\x8B\x1F\x23" // Telegram api.telegram.org TLS public key fingerpring
\*********************************************************************************************/
#define XDRV_40 40
#define TELEGRAM_SEND_RETRY 4 // Retries
#define TELEGRAM_LOOP_WAIT 10 // Seconds
#ifdef USE_MQTT_TLS_CA_CERT
static const uint32_t tls_rx_size = 2048; // since Telegram CA is bigger than 1024 bytes, we need to increase rx buffer
static const uint32_t tls_tx_size = 1024;
#else
static const uint32_t tls_rx_size = 1024;
static const uint32_t tls_tx_size = 1024;
#endif
#include "WiFiClientSecureLightBearSSL.h"
BearSSL::WiFiClientSecure_light *telegramClient = nullptr;
static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT;
struct {
String message[3][6]; // amount of messages read per time (update_id, name_id, name, lastname, chat_id, text)
uint8_t state = 0;
uint8_t index = 0;
uint8_t retry = 0;
uint8_t poll = TELEGRAM_LOOP_WAIT;
uint8_t wait = 0;
bool send_enable = false;
bool recv_enable = false;
bool echo_enable = false;
bool recv_busy = false;
} Telegram;
bool TelegramInit(void) {
bool init_done = false;
if (strlen(SettingsText(SET_TELEGRAM_TOKEN))) {
if (!telegramClient) {
telegramClient = new BearSSL::WiFiClientSecure_light(tls_rx_size, tls_tx_size);
#ifdef USE_MQTT_TLS_CA_CERT
telegramClient->setTrustAnchor(&GoDaddyCAG2_TA);
#else
telegramClient->setPubKeyFingerprint(Telegram_Fingerprint, Telegram_Fingerprint, false); // check server fingerprint
#endif
Telegram.message[0][0]="0"; // Number of received messages
Telegram.message[1][0]="";
Telegram.message[0][1]="0"; // Code of last read Message
AddLog_P2(LOG_LEVEL_INFO, PSTR("TGM: Started"));
}
init_done = true;
}
return init_done;
}
String TelegramConnectToTelegram(String command) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Cmnd %s"), command.c_str());
if (!TelegramInit()) { return ""; }
String response = "";
uint32_t tls_connect_time = millis();
if (telegramClient->connect("api.telegram.org", 443)) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Connected in %d ms, max ThunkStack used %d"), millis() - tls_connect_time, telegramClient->getMaxThunkStackUse());
telegramClient->println("GET /"+command);
String a = "";
char c;
int ch_count=0;
uint32_t now = millis();
bool avail = false;
while (millis() -now < 1500) {
while (telegramClient->available()) {
char c = telegramClient->read();
if (ch_count < 700) {
response = response + c;
ch_count++;
}
avail = true;
}
if (avail) {
break;
}
}
telegramClient->stop();
}
return response;
}
void TelegramGetUpdates(String offset) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getUpdates"));
if (!TelegramInit()) { return; }
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/getUpdates?offset=" + offset;
String response = TelegramConnectToTelegram(command); //recieve reply from telegram.org
// {"ok":true,"result":[]}
// or
// {"ok":true,"result":[
// {"update_id":973125394,
// "message":{"message_id":25,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591877503,
// "text":"M1"
// }
// },
// {"update_id":973125395,
// "message":{"message_id":26,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591877508,
// "text":"M2"
// }
// }
// ]}
// or
// {"ok":true,"result":[
// {"update_id":973125396,
// "message":{"message_id":29,
// "from":{"id":139920293,"is_bot":false,"first_name":"Theo","last_name":"Arends","username":"tjatja","language_code":"nl"},
// "chat":{"id":139920293,"first_name":"Theo","last_name":"Arends","username":"tjatja","type":"private"},
// "date":1591879753,
// "text":"/power toggle",
// "entities":[{"offset":0,"length":6,"type":"bot_command"}]
// }
// }
// ]}
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
// parsing of reply from Telegram into separate received messages
int i = 0; //messages received counter
if (response != "") {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Sent Update request messages up to %s"), offset.c_str());
String a = "";
int ch_count = 0;
String c;
for (uint32_t n = 1; n < response.length() +1; n++) { //Search for each message start
ch_count++;
c = response.substring(n -1, n);
a = a + c;
if (ch_count > 8) {
if (a.substring(ch_count -9) == "update_id") {
if (i > 1) { break; }
Telegram.message[i][0] = a.substring(0, ch_count -11);
a = a.substring(ch_count-11);
i++;
ch_count = 11;
}
}
}
if (1 == i) {
Telegram.message[i][0] = a.substring(0, ch_count); //Assign of parsed message into message matrix if only 1 message)
}
if (i > 1) { i = i -1; }
}
//check result of parsing process
if (response == "") {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Failed to update"));
return;
}
if (0 == i) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: No new messages"));
Telegram.message[0][0] = "0";
} else {
Telegram.message[0][0] = String(i); //returns how many messages are in the array
for (int b = 1; b < i+1; b++) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Msg %d %s"), b, Telegram.message[b][0].c_str());
}
TelegramAnalizeMessage();
}
}
void TelegramAnalizeMessage(void) {
for (uint32_t i = 1; i < Telegram.message[0][0].toInt() +1; i++) {
Telegram.message[i][5] = "";
DynamicJsonBuffer jsonBuffer;
JsonObject &root = jsonBuffer.parseObject(Telegram.message[i][0]);
if (root.success()) {
Telegram.message[i][0] = root["update_id"].as<String>();
Telegram.message[i][1] = root["message"]["from"]["id"].as<String>();
Telegram.message[i][2] = root["message"]["from"]["first_name"].as<String>();
Telegram.message[i][3] = root["message"]["from"]["last_name"].as<String>();
Telegram.message[i][4] = root["message"]["chat"]["id"].as<String>();
Telegram.message[i][5] = root["message"]["text"].as<String>();
}
int id = Telegram.message[Telegram.message[0][0].toInt()][0].toInt() +1;
Telegram.message[0][1] = id; // Write id of last read message
for (int j = 0; j < 6; j++) {
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Parsed%d \"%s\""), j, Telegram.message[i][j].c_str());
}
}
}
bool TelegramSendMessage(String chat_id, String text) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: sendMessage"));
if (!TelegramInit()) { return false; }
bool sent = false;
if (text != "") {
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/sendMessage?chat_id=" + chat_id + "&text=" + text;
String response = TelegramConnectToTelegram(command);
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
if (response.startsWith("{\"ok\":true")) {
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("TGM: Message sent"));
sent = true;
}
}
return sent;
}
/*
void TelegramSendGetMe(void) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: getMe"));
if (!TelegramInit()) { return; }
String _token = SettingsText(SET_TELEGRAM_TOKEN);
String command = "bot" + _token + "/getMe";
String response = TelegramConnectToTelegram(command);
// {"ok":true,"result":{"id":1179906608,"is_bot":true,"first_name":"Tasmota","username":"tasmota_bot","can_join_groups":true,"can_read_all_group_messages":false,"supports_inline_queries":false}}
// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str());
}
*/
String TelegramExecuteCommand(const char *svalue) {
String response = "";
uint32_t curridx = web_log_index;
ExecuteCommand(svalue, SRC_CHAT);
if (web_log_index != curridx) {
uint32_t counter = curridx;
response = F("{");
bool cflg = false;
do {
char* tmp;
size_t len;
GetLog(counter, &tmp, &len);
if (len) {
// [14:49:36 MQTT: stat/wemos5/RESULT = {"POWER":"OFF"}] > [{"POWER":"OFF"}]
char* JSON = (char*)memchr(tmp, '{', len);
if (JSON) { // Is it a JSON message (and not only [15:26:08 MQT: stat/wemos5/POWER = O])
size_t JSONlen = len - (JSON - tmp);
if (JSONlen > sizeof(mqtt_data)) { JSONlen = sizeof(mqtt_data); }
char stemp[JSONlen];
strlcpy(stemp, JSON +1, JSONlen -2);
if (cflg) { response += F(","); }
response += stemp;
cflg = true;
}
}
counter++;
counter &= 0xFF;
if (!counter) counter++; // Skip 0 as it is not allowed
} while (counter != web_log_index);
response += F("}");
} else {
response = F("{\"" D_RSLT_WARNING "\":\"" D_ENABLE_WEBLOG_FOR_RESPONSE "\"}");
}
return response;
}
void TelegramLoop(void) {
if (!global_state.wifi_down && (Telegram.recv_enable || Telegram.echo_enable)) {
switch (Telegram.state) {
case 0:
TelegramInit();
Telegram.state++;
break;
case 1:
TelegramGetUpdates(Telegram.message[0][1]); // launch API GetUpdates up to xxx message
Telegram.index = 1;
Telegram.retry = TELEGRAM_SEND_RETRY;
Telegram.state++;
break;
case 2:
if (Telegram.echo_enable) {
if (Telegram.retry && (Telegram.index < Telegram.message[0][0].toInt() + 1)) {
if (TelegramSendMessage(Telegram.message[Telegram.index][4], Telegram.message[Telegram.index][5])) {
Telegram.index++;
Telegram.retry = TELEGRAM_SEND_RETRY;
} else {
Telegram.retry--;
}
} else {
Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
Telegram.wait = Telegram.poll;
Telegram.state++;
}
} else {
if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) {
String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str());
if (logging.length() > 0) {
TelegramSendMessage(Telegram.message[Telegram.index][4], logging);
}
}
Telegram.message[0][0] = ""; // All messages have been replied - reset new messages
Telegram.wait = Telegram.poll;
Telegram.state++;
}
break;
case 3:
if (Telegram.wait) {
Telegram.wait--;
} else {
Telegram.state = 1;
}
}
}
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
#define D_CMND_TMSTATE "State"
#define D_CMND_TMPOLL "Poll"
#define D_CMND_TMSEND "Send"
#define D_CMND_TMTOKEN "Token"
#define D_CMND_TMCHATID "ChatId"
const char kTelegramCommands[] PROGMEM = "Tm|" // Prefix
D_CMND_TMSTATE "|" D_CMND_TMPOLL "|" D_CMND_TMTOKEN "|" D_CMND_TMCHATID "|" D_CMND_TMSEND;
void (* const TelegramCommand[])(void) PROGMEM = {
&CmndTmState, &CmndTmPoll, &CmndTmToken, &CmndTmChatId, &CmndTmSend };
void CmndTmState(void) {
if (XdrvMailbox.data_len > 0) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 6)) {
switch (XdrvMailbox.payload) {
case 0: // Off
case 1: // On
Telegram.send_enable = XdrvMailbox.payload &1;
break;
case 2: // Off
case 3: // On
Telegram.recv_enable = XdrvMailbox.payload &1;
break;
case 4: // Off
case 5: // On
Telegram.echo_enable = XdrvMailbox.payload &1;
break;
}
}
}
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":{\"Send\":\"%s\",\"Receive\":\"%s\",\"Echo\":\"%s\"}}"),
XdrvMailbox.command, GetStateText(Telegram.send_enable), GetStateText(Telegram.recv_enable), GetStateText(Telegram.echo_enable));
}
void CmndTmPoll(void) {
if ((XdrvMailbox.payload >= 4) && (XdrvMailbox.payload <= 300)) {
Telegram.poll = XdrvMailbox.payload;
if (Telegram.poll < Telegram.wait) {
Telegram.wait = Telegram.poll;
}
}
ResponseCmndNumber(Telegram.poll);
}
void CmndTmToken(void) {
if (XdrvMailbox.data_len > 0) {
SettingsUpdateText(SET_TELEGRAM_TOKEN, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
}
ResponseCmndChar(SettingsText(SET_TELEGRAM_TOKEN));
}
void CmndTmChatId(void) {
if (XdrvMailbox.data_len > 0) {
SettingsUpdateText(SET_TELEGRAM_CHATID, ('"' == XdrvMailbox.data[0]) ? "" : XdrvMailbox.data);
}
ResponseCmndChar(SettingsText(SET_TELEGRAM_CHATID));
}
void CmndTmSend(void) {
if (!Telegram.send_enable || !strlen(SettingsText(SET_TELEGRAM_CHATID))) {
ResponseCmndChar(D_JSON_FAILED);
return;
}
if (XdrvMailbox.data_len > 0) {
String message = XdrvMailbox.data;
String chat_id = SettingsText(SET_TELEGRAM_CHATID);
if (!TelegramSendMessage(chat_id, message)) {
ResponseCmndChar(D_JSON_FAILED);
return;
}
}
ResponseCmndDone();
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv40(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_EVERY_SECOND:
TelegramLoop();
break;
case FUNC_COMMAND:
result = DecodeCommand(kTelegramCommands, TelegramCommand);
break;
}
return result;
}
#endif // USE_TELEGRAM

View File

@ -59,8 +59,7 @@ struct CSE {
bool received = false; bool received = false;
} Cse; } Cse;
void CseReceived(void) void CseReceived(void) {
{
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// F2 5A 02 F7 60 00 03 61 00 40 10 05 72 40 51 A6 58 63 10 1B E1 7F 4D 4E - F2 = Power cycle exceeds range - takes too long - No load // F2 5A 02 F7 60 00 03 61 00 40 10 05 72 40 51 A6 58 63 10 1B E1 7F 4D 4E - F2 = Power cycle exceeds range - takes too long - No load
// 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - 55 = Ok, 61 = Power not valid (load below 5W) // 55 5A 02 F7 60 00 03 5A 00 40 10 04 8B 9F 51 A6 58 18 72 75 61 AC A1 30 - 55 = Ok, 61 = Power not valid (load below 5W)
@ -69,7 +68,7 @@ void CseReceived(void)
uint8_t header = Cse.rx_buffer[0]; uint8_t header = Cse.rx_buffer[0];
if ((header & 0xFC) == 0xFC) { if ((header & 0xFC) == 0xFC) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware")); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: Abnormal hardware"));
return; return;
} }
@ -142,8 +141,7 @@ void CseReceived(void)
} }
} }
bool CseSerialInput(void) bool CseSerialInput(void) {
{
while (CseSerial->available()) { while (CseSerial->available()) {
yield(); yield();
uint8_t serial_in_byte = CseSerial->read(); uint8_t serial_in_byte = CseSerial->read();
@ -162,12 +160,12 @@ bool CseSerialInput(void)
Cse.received = false; Cse.received = false;
return true; return true;
} else { } else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
do { // Sync buffer with data (issue #1907 and #3425) do { // Sync buffer with data (issue #1907 and #3425)
memmove(Cse.rx_buffer, Cse.rx_buffer +1, 24); memmove(Cse.rx_buffer, Cse.rx_buffer +1, 24);
Cse.byte_counter--; Cse.byte_counter--;
} while ((Cse.byte_counter > 2) && (0x5A != Cse.rx_buffer[1])); } while ((Cse.byte_counter > 2) && (0x5A != Cse.rx_buffer[1]));
if (0x5A != Cse.rx_buffer[1]) { if (0x5A != Cse.rx_buffer[1]) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: " D_CHECKSUM_FAILURE));
Cse.received = false; Cse.received = false;
Cse.byte_counter = 0; Cse.byte_counter = 0;
} }
@ -186,34 +184,31 @@ bool CseSerialInput(void)
/********************************************************************************************/ /********************************************************************************************/
void CseEverySecond(void) void CseEverySecond(void) {
{
if (Energy.data_valid[0] > ENERGY_WATCHDOG) { if (Energy.data_valid[0] > ENERGY_WATCHDOG) {
Cse.voltage_cycle = 0; Cse.voltage_cycle = 0;
Cse.current_cycle = 0; Cse.current_cycle = 0;
Cse.power_cycle = 0; Cse.power_cycle = 0;
} else { } else {
long cf_frequency = 0;
if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) { if (CSE_PULSES_NOT_INITIALIZED == Cse.cf_pulses_last_time) {
Cse.cf_pulses_last_time = Cse.cf_pulses; // Init after restart Cse.cf_pulses_last_time = Cse.cf_pulses; // Init after restart
} else { } else {
if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 65535 pulses uint32_t cf_pulses = 0;
cf_frequency = (65536 - Cse.cf_pulses_last_time) + Cse.cf_pulses; if (Cse.cf_pulses < Cse.cf_pulses_last_time) { // Rolled over after 0xFFFF (65535) pulses
cf_pulses = (0x10000 - Cse.cf_pulses_last_time) + Cse.cf_pulses;
} else { } else {
cf_frequency = Cse.cf_pulses - Cse.cf_pulses_last_time; cf_pulses = Cse.cf_pulses - Cse.cf_pulses_last_time;
} }
if (cf_frequency && Energy.active_power[0]) { if (cf_pulses && Energy.active_power[0]) {
unsigned long delta = (cf_frequency * Settings.energy_power_calibration) / 36; uint32_t delta = (cf_pulses * Settings.energy_power_calibration) / 36;
// prevent invalid load delta steps even checksum is valid (issue #5789): // prevent invalid load delta steps even checksum is valid (issue #5789):
// if (delta <= (3680*100/36) * 10 ) { // max load for S31/Pow R2: 3.68kW
// prevent invalid load delta steps even checksum is valid but allow up to 4kW (issue #7155): // prevent invalid load delta steps even checksum is valid but allow up to 4kW (issue #7155):
if (delta <= (4000*100/36) * 10 ) { // max load for S31/Pow R2: 4.00kW if (delta <= (4000 * 1000 / 36)) { // max load for S31/Pow R2: 4.00kW
Cse.cf_pulses_last_time = Cse.cf_pulses; Cse.cf_pulses_last_time = Cse.cf_pulses;
Energy.kWhtoday_delta += delta; Energy.kWhtoday_delta += delta;
} }
else { else {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("CSE: Load overflow")); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("CSE: Overload"));
Cse.cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED; Cse.cf_pulses_last_time = CSE_PULSES_NOT_INITIALIZED;
} }
EnergyUpdateToday(); EnergyUpdateToday();
@ -222,8 +217,7 @@ void CseEverySecond(void)
} }
} }
void CseSnsInit(void) void CseSnsInit(void) {
{
// Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
// CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1); // CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), Pin(GPIO_CSE7766_TX), 1);
CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1); CseSerial = new TasmotaSerial(Pin(GPIO_CSE7766_RX), -1, 1);
@ -241,8 +235,7 @@ void CseSnsInit(void)
} }
} }
void CseDrvInit(void) void CseDrvInit(void) {
{
// if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) { // if (PinUsed(GPIO_CSE7766_RX) && PinUsed(GPIO_CSE7766_TX)) {
if (PinUsed(GPIO_CSE7766_RX)) { if (PinUsed(GPIO_CSE7766_RX)) {
Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE)); Cse.rx_buffer = (uint8_t*)(malloc(CSE_BUFFER_SIZE));
@ -252,8 +245,7 @@ void CseDrvInit(void)
} }
} }
bool CseCommand(void) bool CseCommand(void) {
{
bool serviced = true; bool serviced = true;
if (CMND_POWERSET == Energy.command_code) { if (CMND_POWERSET == Energy.command_code) {
@ -280,15 +272,14 @@ bool CseCommand(void)
* Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
bool Xnrg02(uint8_t function) bool Xnrg02(uint8_t function) {
{
bool result = false; bool result = false;
switch (function) { switch (function) {
case FUNC_LOOP: case FUNC_LOOP:
if (CseSerial) { CseSerialInput(); } if (CseSerial) { CseSerialInput(); }
break; break;
case FUNC_ENERGY_EVERY_SECOND: case FUNC_EVERY_SECOND:
CseEverySecond(); CseEverySecond();
break; break;
case FUNC_COMMAND: case FUNC_COMMAND:

View File

@ -33,6 +33,8 @@
#define BL0940_UREF 33000 #define BL0940_UREF 33000
#define BL0940_IREF 2750 #define BL0940_IREF 2750
#define BL0940_PULSES_NOT_INITIALIZED -1
#define BL0940_BUFFER_SIZE 36 #define BL0940_BUFFER_SIZE 36
#define BL0940_WRITE_COMMAND 0xA0 // 0xA8 according to documentation #define BL0940_WRITE_COMMAND 0xA0 // 0xA8 according to documentation
@ -55,11 +57,13 @@ struct BL0940 {
long voltage = 0; long voltage = 0;
long current = 0; long current = 0;
long power = 0; long power = 0;
// long power_cycle_first = 0; long power_cycle_first = 0;
// long cf_pulses = 0; long cf_pulses = 0;
long cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED;
float temperature; float temperature;
int byte_counter = 0; int byte_counter = 0;
uint16_t tps1 = 0;
uint8_t *rx_buffer = nullptr; uint8_t *rx_buffer = nullptr;
bool received = false; bool received = false;
} Bl0940; } Bl0940;
@ -78,22 +82,31 @@ void Bl0940Received(void) {
// 55 B9 33 00 DE 45 00 94 02 00 CF E4 70 63 02 00 6C 4C 00 13 01 00 09 00 00 00 00 00 E4 01 00 FE 03 00 72 // 55 B9 33 00 DE 45 00 94 02 00 CF E4 70 63 02 00 6C 4C 00 13 01 00 09 00 00 00 00 00 E4 01 00 FE 03 00 72
// Hd IFRms--- Current- Reserved Voltage- Reserved Power--- Reserved CF------ Reserved TPS1---- TPS2---- Ck // Hd IFRms--- Current- Reserved Voltage- Reserved Power--- Reserved CF------ Reserved TPS1---- TPS2---- Ck
if (Bl0940.rx_buffer[0] != BL0940_PACKET_HEADER) { uint16_t tps1 = Bl0940.rx_buffer[29] << 8 | Bl0940.rx_buffer[28]; // TPS1 unsigned
AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: Invalid data")); if ((Bl0940.rx_buffer[0] != BL0940_PACKET_HEADER) || // Bad header
(Bl0940.tps1 && ((tps1 < (Bl0940.tps1 -10)) || (tps1 > (Bl0940.tps1 +10)))) // Invalid temperature change
) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Invalid data"));
return; return;
} }
Bl0940.voltage = Bl0940.rx_buffer[12] << 16 | Bl0940.rx_buffer[11] << 8 | Bl0940.rx_buffer[10]; Bl0940.tps1 = tps1;
Bl0940.current = Bl0940.rx_buffer[6] << 16 | Bl0940.rx_buffer[5] << 8 | Bl0940.rx_buffer[4]; float t = ((170.0f/448.0f)*(((float)Bl0940.tps1/2.0f)-32.0f))-45.0f;
Bl0940.power = Bl0940.rx_buffer[18] << 16 | Bl0940.rx_buffer[17] << 8 | Bl0940.rx_buffer[16];
// Bl0940.cf_pulses = Bl0940.rx_buffer[24] << 16 | Bl0940.rx_buffer[23] << 8 | Bl0940.rx_buffer[22];
uint16_t tps1 = Bl0940.rx_buffer[29] << 8 | Bl0940.rx_buffer[28];
float t = ((170.0f/448.0f)*(((float)tps1/2.0f)-32.0f))-45.0f;
Bl0940.temperature = ConvertTemp(t); Bl0940.temperature = ConvertTemp(t);
Bl0940.voltage = Bl0940.rx_buffer[12] << 16 | Bl0940.rx_buffer[11] << 8 | Bl0940.rx_buffer[10]; // V_RMS unsigned
Bl0940.current = Bl0940.rx_buffer[6] << 16 | Bl0940.rx_buffer[5] << 8 | Bl0940.rx_buffer[4]; // I_RMS unsigned
int32_t power = Bl0940.rx_buffer[18] << 24 | Bl0940.rx_buffer[17] << 16 | Bl0940.rx_buffer[16] << 8; // WATT signed
Bl0940.power = abs(power) >> 8; // WATT unsigned
int32_t cf_cnt = Bl0940.rx_buffer[24] << 24 | Bl0940.rx_buffer[23] << 16 | Bl0940.rx_buffer[22] << 8; // CF_CNT signed
Bl0940.cf_pulses = abs(cf_cnt) >> 8;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: U %d, I %d, P %d, C %d, T %d"),
Bl0940.voltage, Bl0940.current, Bl0940.power, Bl0940.cf_pulses, Bl0940.tps1);
if (Energy.power_on) { // Powered on if (Energy.power_on) { // Powered on
Energy.voltage[0] = (float)Bl0940.voltage / Settings.energy_voltage_calibration; Energy.voltage[0] = (float)Bl0940.voltage / Settings.energy_voltage_calibration;
if (power != 0) { if (power && (Bl0940.power > Settings.energy_power_calibration)) { // We need at least 1W
Energy.active_power[0] = (float)Bl0940.power / Settings.energy_power_calibration; Energy.active_power[0] = (float)Bl0940.power / Settings.energy_power_calibration;
Energy.current[0] = (float)Bl0940.current / (Settings.energy_current_calibration * 100); Energy.current[0] = (float)Bl0940.current / (Settings.energy_current_calibration * 100);
} else { } else {
@ -131,13 +144,12 @@ bool Bl0940SerialInput(void) {
Bl0940.received = false; Bl0940.received = false;
return true; return true;
} else { } else {
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE));
do { // Sync buffer with data (issue #1907 and #3425) do { // Sync buffer with data (issue #1907 and #3425)
memmove(Bl0940.rx_buffer, Bl0940.rx_buffer +1, BL0940_BUFFER_SIZE -1); memmove(Bl0940.rx_buffer, Bl0940.rx_buffer +1, BL0940_BUFFER_SIZE -1);
Bl0940.byte_counter--; Bl0940.byte_counter--;
} while ((Bl0940.byte_counter > 1) && (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0])); } while ((Bl0940.byte_counter > 1) && (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]));
if (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]) { if (BL0940_PACKET_HEADER != Bl0940.rx_buffer[0]) {
AddLog_P(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE)); AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: " D_CHECKSUM_FAILURE));
Bl0940.received = false; Bl0940.received = false;
Bl0940.byte_counter = 0; Bl0940.byte_counter = 0;
} }
@ -155,12 +167,41 @@ void Bl0940EverySecond(void) {
Bl0940.current = 0; Bl0940.current = 0;
Bl0940.power = 0; Bl0940.power = 0;
} else { } else {
/*
// Calculate energy by using active power
if (Energy.active_power[0]) { if (Energy.active_power[0]) {
Energy.kWhtoday_delta += (Energy.active_power[0] * 1000) / 36; Energy.kWhtoday_delta += (Energy.active_power[0] * 1000) / 36;
EnergyUpdateToday(); EnergyUpdateToday();
} }
*/
// Calculate energy by using active energy pulse count
if (BL0940_PULSES_NOT_INITIALIZED == Bl0940.cf_pulses_last_time) {
Bl0940.cf_pulses_last_time = Bl0940.cf_pulses; // Init after restart
} else {
uint32_t cf_pulses = 0;
if (Bl0940.cf_pulses < Bl0940.cf_pulses_last_time) { // Rolled over after 0xFFFFFF (16777215) pulses
cf_pulses = (0x1000000 - Bl0940.cf_pulses_last_time) + Bl0940.cf_pulses;
} else {
cf_pulses = Bl0940.cf_pulses - Bl0940.cf_pulses_last_time;
}
if (cf_pulses && Energy.active_power[0]) {
uint32_t watt256 = (1638400 * 256) / Settings.energy_power_calibration;
uint32_t delta = (cf_pulses * watt256) / 36;
if (delta <= (4000 * 1000 / 36)) { // max load for SHP10: 4.00kW (3.68kW)
Bl0940.cf_pulses_last_time = Bl0940.cf_pulses;
Energy.kWhtoday_delta += delta;
} else {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Overload"));
Bl0940.cf_pulses_last_time = BL0940_PULSES_NOT_INITIALIZED;
}
EnergyUpdateToday();
}
}
} }
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("BL9: Poll"));
Bl0940Serial->flush(); Bl0940Serial->flush();
Bl0940Serial->write(BL0940_READ_COMMAND); Bl0940Serial->write(BL0940_READ_COMMAND);
Bl0940Serial->write(BL0940_FULL_PACKET); Bl0940Serial->write(BL0940_FULL_PACKET);
@ -169,7 +210,7 @@ void Bl0940EverySecond(void) {
void Bl0940SnsInit(void) { void Bl0940SnsInit(void) {
// Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions // Software serial init needs to be done here as earlier (serial) interrupts may lead to Exceptions
Bl0940Serial = new TasmotaSerial(Pin(GPIO_BL0940_RX), Pin(GPIO_TXD), 1); Bl0940Serial = new TasmotaSerial(Pin(GPIO_BL0940_RX), Pin(GPIO_TXD), 1);
if (Bl0940Serial->begin(4800, 2)) { if (Bl0940Serial->begin(4800, 1)) {
if (Bl0940Serial->hardwareSerial()) { if (Bl0940Serial->hardwareSerial()) {
ClaimSerial(); ClaimSerial();
} }
@ -226,8 +267,7 @@ bool Bl0940Command(void) {
return serviced; return serviced;
} }
void Bl0940Show(bool json) void Bl0940Show(bool json) {
{
char temperature[33]; char temperature[33];
dtostrfd(Bl0940.temperature, Settings.flag2.temperature_resolution, temperature); dtostrfd(Bl0940.temperature, Settings.flag2.temperature_resolution, temperature);
@ -252,15 +292,14 @@ void Bl0940Show(bool json)
* Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
bool Xnrg14(uint8_t function) bool Xnrg14(uint8_t function) {
{
bool result = false; bool result = false;
switch (function) { switch (function) {
case FUNC_LOOP: case FUNC_LOOP:
if (Bl0940Serial) { Bl0940SerialInput(); } if (Bl0940Serial) { Bl0940SerialInput(); }
break; break;
case FUNC_ENERGY_EVERY_SECOND: case FUNC_EVERY_SECOND:
Bl0940EverySecond(); Bl0940EverySecond();
break; break;
case FUNC_JSON_APPEND: case FUNC_JSON_APPEND:

View File

@ -87,7 +87,7 @@ void Sgp30Update(void) // Perform every second to ensure proper operation of th
if (!sgp.IAQmeasure()) { if (!sgp.IAQmeasure()) {
return; // Measurement failed return; // Measurement failed
} }
if (global_update && (global_humidity > 0) && (global_temperature != 9999)) { if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
// abs hum in mg/m3 // abs hum in mg/m3
sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit()); sgp30_abshum=sgp30_AbsoluteHumidity(global_temperature,global_humidity,TempUnit());
sgp.setHumidity(sgp30_abshum*1000); sgp.setHumidity(sgp30_abshum*1000);
@ -118,14 +118,14 @@ void Sgp30Show(bool json)
{ {
if (sgp30_ready) { if (sgp30_ready) {
char abs_hum[33]; char abs_hum[33];
if (global_update && global_humidity>0 && global_temperature!=9999) { if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
// has humidity + temperature // has humidity + temperature
dtostrfd(sgp30_abshum,4,abs_hum); dtostrfd(sgp30_abshum,4,abs_hum);
} }
if (json) { if (json) {
ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC); ResponseAppend_P(PSTR(",\"SGP30\":{\"" D_JSON_ECO2 "\":%d,\"" D_JSON_TVOC "\":%d"), sgp.eCO2, sgp.TVOC);
if (global_update && global_humidity>0 && global_temperature!=9999) { if (global_update && global_humidity>0 && !isnan(global_temperature)) {
ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum); ResponseAppend_P(PSTR(",\"" D_JSON_AHUM "\":%s"),abs_hum);
} }
ResponseJsonEnd(); ResponseJsonEnd();

View File

@ -65,7 +65,9 @@ void CCS811Update(void) // Perform every n second
TVOC = ccs.getTVOC(); TVOC = ccs.getTVOC();
eCO2 = ccs.geteCO2(); eCO2 = ccs.geteCO2();
CCS811_ready = 1; CCS811_ready = 1;
if (global_update && global_humidity>0 && global_temperature!=9999) { ccs.setEnvironmentalData((uint8_t)global_humidity, global_temperature); } if (global_update && (global_humidity > 0) && !isnan(global_temperature)) {
ccs.setEnvironmentalData((uint8_t)global_humidity, global_temperature);
}
ecnt = 0; ecnt = 0;
} }
} else { } else {

View File

@ -20,6 +20,8 @@
Version Date Action Description Version Date Action Description
-------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------
1.0.0.2 20200611 changed - bugfix: decouple restart of the work loop from FUNC_JSON_APPEND callback
---
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
changed - double send address change only for fw>0x25 changed - double send address change only for fw>0x25
changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS changed - use DEBUG_SENSOR_LOG, change ILLUMINANCE to DARKNESS
@ -300,7 +302,7 @@ void ChirpServiceAllSensors(uint8_t job){
void ChirpEvery100MSecond(void) void ChirpEvery100MSecond(void)
{ {
// DEBUG_SENSOR_LOG(PSTR("CHIRP: every second")); // DEBUG_SENSOR_LOG(PSTR("CHIRP: every 100 mseconds, counter: %u, next job: %u"),chirp_timeout_count,chirp_next_job);
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
@ -377,10 +379,11 @@ void ChirpEvery100MSecond(void)
break; break;
case 13: case 13:
DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE")); DEBUG_SENSOR_LOG(PSTR("CHIRP: paused, waiting for TELE"));
chirp_next_job++;
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 - 16) * 10; // sync it with the TELEPERIOD, we need about up to 16 seconds to measure
DEBUG_SENSOR_LOG(PSTR("CHIRP: timeout 1/10 sec: %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{ else{
@ -533,7 +536,6 @@ bool Xsns48(uint8_t function)
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
break; break;
#ifdef USE_WEBSERVER #ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR: case FUNC_WEB_SENSOR:

View File

@ -87,6 +87,9 @@ struct IBEACON {
struct IBEACON_UID { struct IBEACON_UID {
char MAC[12]; char MAC[12];
char RSSI[4]; char RSSI[4];
char UID[32];
char MAJOR[4];
char MINOR[4];
uint8_t FLAGS; uint8_t FLAGS;
uint8_t TIME; uint8_t TIME;
} ibeacons[MAX_IBEACONS]; } ibeacons[MAX_IBEACONS];
@ -132,7 +135,7 @@ void hm17_every_second(void) {
ibeacons[cnt].TIME++; ibeacons[cnt].TIME++;
if (ibeacons[cnt].TIME>IB_TIMEOUT_TIME) { if (ibeacons[cnt].TIME>IB_TIMEOUT_TIME) {
ibeacons[cnt].FLAGS=0; ibeacons[cnt].FLAGS=0;
ibeacon_mqtt(ibeacons[cnt].MAC,"0000"); ibeacon_mqtt(ibeacons[cnt].MAC,"0000",ibeacons[cnt].UID,ibeacons[cnt].MAJOR,ibeacons[cnt].MINOR);
} }
} }
} }
@ -210,6 +213,9 @@ uint32_t ibeacon_add(struct IBEACON *ib) {
if (!ibeacons[cnt].FLAGS) { if (!ibeacons[cnt].FLAGS) {
memcpy(ibeacons[cnt].MAC,ib->MAC,12); memcpy(ibeacons[cnt].MAC,ib->MAC,12);
memcpy(ibeacons[cnt].RSSI,ib->RSSI,4); memcpy(ibeacons[cnt].RSSI,ib->RSSI,4);
memcpy(ibeacons[cnt].UID,ib->UID,32);
memcpy(ibeacons[cnt].MAJOR,ib->MAJOR,4);
memcpy(ibeacons[cnt].MINOR,ib->MINOR,4);
ibeacons[cnt].FLAGS=1; ibeacons[cnt].FLAGS=1;
ibeacons[cnt].TIME=0; ibeacons[cnt].TIME=0;
return 1; return 1;
@ -400,7 +406,7 @@ hm17_v110:
memcpy(ib.RSSI,&hm17_sbuffer[8+8+1+32+1+4+4+2+1+12+1],4); memcpy(ib.RSSI,&hm17_sbuffer[8+8+1+32+1+4+4+2+1+12+1],4);
if (ibeacon_add(&ib)) { if (ibeacon_add(&ib)) {
ibeacon_mqtt(ib.MAC,ib.RSSI); ibeacon_mqtt(ib.MAC,ib.RSSI,ib.UID,ib.MAJOR,ib.MINOR);
} }
hm17_sbclr(); hm17_sbclr();
hm17_result=1; hm17_result=1;
@ -560,15 +566,30 @@ void ib_sendbeep(void) {
hm17_sendcmd(HM17_CON); hm17_sendcmd(HM17_CON);
} }
void ibeacon_mqtt(const char *mac,const char *rssi) { void ibeacon_mqtt(const char *mac,const char *rssi,const char *uid,const char *major,const char *minor) {
char s_mac[14]; char s_mac[14];
char s_uid[34];
char s_major[6];
char s_minor[6];
char s_rssi[6]; char s_rssi[6];
memcpy(s_mac,mac,12); memcpy(s_mac,mac,12);
s_mac[12]=0; s_mac[12]=0;
memcpy(s_uid,uid,32);
s_uid[32]=0;
memcpy(s_major,major,4);
s_major[4]=0;
memcpy(s_minor,minor,4);
s_minor[4]=0;
memcpy(s_rssi,rssi,4); memcpy(s_rssi,rssi,4);
s_rssi[4]=0; s_rssi[4]=0;
int16_t n_rssi=atoi(s_rssi); int16_t n_rssi=atoi(s_rssi);
ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"RSSI\":%d}}"),s_mac,n_rssi); // if uid == all zeros, take mac
if (!strncmp_P(s_uid,PSTR("00000000000000000000000000000000"),32)) {
ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"UID\":\"%s\",\"MAJOR\":\"%s\",\"MINOR\":\"%s\",\"RSSI\":%d}}"),s_mac,s_uid,s_major,s_minor,n_rssi);
} else {
ResponseTime_P(PSTR(",\"" D_CMND_IBEACON "_%s\":{\"MAJOR\":\"%s\",\"MINOR\":\"%s\",\"RSSI\":%d}}"),s_uid,s_major,s_minor,n_rssi);
}
MqttPublishTeleSensor(); MqttPublishTeleSensor();
} }

View File

@ -2405,12 +2405,13 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
if (!rflg) { if (!rflg) {
*ucp++=0; *ucp++=0;
*ucp++=2; *ucp++=2;
slen+=2;
} }
// append crc // append crc
uint16_t crc = MBUS_calculateCRC(sbuff,6); uint16_t crc = MBUS_calculateCRC(sbuff,slen);
*ucp++=lowByte(crc); *ucp++=lowByte(crc);
*ucp++=highByte(crc); *ucp++=highByte(crc);
slen+=4; slen+=2;
} }
if (script_meter_desc[meter].type=='o') { if (script_meter_desc[meter].type=='o') {
for (uint32_t cnt=0;cnt<slen;cnt++) { for (uint32_t cnt=0;cnt<slen;cnt++) {

View File

@ -40,27 +40,27 @@ const char JSON_SNS_VEML7700[] PROGMEM = ",\"%s\":{\"" D_JSON_ILLUMINANCE "\":%d
#define D_CMND_VEML7700_PWR "power" #define D_CMND_VEML7700_PWR "power"
#define D_CMND_VEML7700_GAIN "gain" #define D_CMND_VEML7700_GAIN "gain"
#define D_CMND_VEML7700_INTTIME "inttime" #define D_CMND_VEML7700_INTTIME "inttime"
#define D_CMND_VEML7700_PERSIST "persist"
const char S_JSON_VEML7700_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_VEML7700 "\":{\"%s\":%d}}"; const char S_JSON_VEML7700_COMMAND_NVALUE[] PROGMEM = "{\"" D_NAME_VEML7700 "\":{\"%s\":%d}}";
const char kVEML7700_Commands[] PROGMEM = D_CMND_VEML7700_PWR "|" D_CMND_VEML7700_GAIN "|" D_CMND_VEML7700_INTTIME; const char kVEML7700_Commands[] PROGMEM = D_CMND_VEML7700_PWR "|" D_CMND_VEML7700_GAIN "|" D_CMND_VEML7700_INTTIME "|" D_CMND_VEML7700_PERSIST;
enum VEML7700_Commands { // commands for Console enum VEML7700_Commands { // commands for Console
CMND_VEML7700_PWR, CMND_VEML7700_PWR,
CMND_VEML7700_GAIN, CMND_VEML7700_GAIN,
CMND_VEML7700_SET_IT, CMND_VEML7700_SET_IT,
}; CMND_VEML7700_PERSIST,
};
struct VEML7700STRUCT struct VEML7700STRUCT
{ {
bool active = 0;
char types[9] = D_NAME_VEML7700; char types[9] = D_NAME_VEML7700;
uint8_t address = VEML7700_I2CADDR_DEFAULT; uint8_t address = VEML7700_I2CADDR_DEFAULT;
//uint16_t lux = 0; uint32_t lux_normalized = 0;
//uint16_t white = 0; uint32_t white_normalized = 0;
uint16_t lux_normalized = 0;
uint16_t white_normalized = 0;
} veml7700_sensor; } veml7700_sensor;
uint8_t veml7700_active = 0;
/********************************************************************************************/ /********************************************************************************************/
@ -68,7 +68,7 @@ void VEML7700Detect(void) {
if (!I2cSetDevice(veml7700_sensor.address)) return; if (!I2cSetDevice(veml7700_sensor.address)) return;
if (veml7700.begin()) { if (veml7700.begin()) {
I2cSetActiveFound(veml7700_sensor.address, veml7700_sensor.types); I2cSetActiveFound(veml7700_sensor.address, veml7700_sensor.types);
veml7700_active = 1; veml7700_sensor.active = 1;
} }
} }
@ -97,10 +97,8 @@ uint8_t VEML7700TranslateItInt (uint16_t ittimems){
} }
void VEML7700EverySecond(void) { void VEML7700EverySecond(void) {
veml7700_sensor.lux_normalized = (uint16_t) veml7700.readLuxNormalized(); veml7700_sensor.lux_normalized = (uint32_t) veml7700.readLuxNormalized();
veml7700_sensor.white_normalized = (uint16_t) veml7700.readWhiteNormalized(); veml7700_sensor.white_normalized = (uint32_t) veml7700.readWhiteNormalized();
//veml7700_sensor.lux = (uint16_t) veml7700.readLux();
//veml7700_sensor.white = (uint16_t) veml7700.readWhite();
} }
void VEML7700Show(bool json) void VEML7700Show(bool json)
@ -152,6 +150,14 @@ bool VEML7700Cmd(void) {
Response_P(S_JSON_VEML7700_COMMAND_NVALUE, command, dataret); Response_P(S_JSON_VEML7700_COMMAND_NVALUE, command, dataret);
} }
break; break;
case CMND_VEML7700_PERSIST:
if (XdrvMailbox.data_len) {
if (4 >= XdrvMailbox.payload) {
veml7700.setPersistence(XdrvMailbox.payload);
}
}
Response_P(S_JSON_VEML7700_COMMAND_NVALUE, command, veml7700.getPersistence());
break;
default: default:
return false; return false;
} }
@ -174,7 +180,7 @@ bool Xsns71(uint8_t function)
if (FUNC_INIT == function) { if (FUNC_INIT == function) {
VEML7700Detect(); VEML7700Detect();
} }
else if (veml7700_active) { else if (veml7700_sensor.active) {
switch (function) { switch (function) {
case FUNC_EVERY_SECOND: case FUNC_EVERY_SECOND:
VEML7700EverySecond(); VEML7700EverySecond();

178
tasmota/xsns_73_hp303b.ino Normal file
View File

@ -0,0 +1,178 @@
/*
xsns_72_hp303b.ino - HP303B digital barometric air pressure sensor support for Tasmota
Copyright (C) 2020 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_I2C
#ifdef USE_HP303B
/*********************************************************************************************\
* HP303B - Pressure and temperature sensor
*
* Source: Lolin LOLIN_HP303B_Library
*
* I2C Address: 0x77 or 0x76
\*********************************************************************************************/
#define XSNS_73 73
#define XI2C_52 52 // See I2CDEVICES.md
#define HP303B_MAX_SENSORS 2
#define HP303B_START_ADDRESS 0x76
#include <LOLIN_HP303B.h>
// HP303B Object
LOLIN_HP303B HP303BSensor = LOLIN_HP303B();
struct {
int16_t oversampling = 7;
char types[7] = "HP303B";
uint8_t count = 0;
} hp303b_cfg;
struct BHP303B {
float temperature = NAN;
float pressure = NAN;
uint8_t address;
uint8_t valid = 0;
} hp303b_sensor[HP303B_MAX_SENSORS];
/*********************************************************************************************/
bool HP303B_Read(uint32_t hp303b_idx) {
if (hp303b_sensor[hp303b_idx].valid) { hp303b_sensor[hp303b_idx].valid--; }
float t;
if (HP303BSensor.measureTempOnce(t, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling) != 0) {
return false;
}
float p;
if (HP303BSensor.measurePressureOnce(p, hp303b_sensor[hp303b_idx].address, hp303b_cfg.oversampling) != 0) {
return false;
}
hp303b_sensor[hp303b_idx].temperature = (float)ConvertTemp(t);
hp303b_sensor[hp303b_idx].pressure = (float)ConvertPressure(p / 100); // Conversion to hPa
hp303b_sensor[hp303b_idx].valid = SENSOR_MAX_MISS;
return true;
}
/********************************************************************************************/
void HP303B_Detect(void) {
for (uint32_t i = 0; i < HP303B_MAX_SENSORS; i++) {
if (!I2cSetDevice(HP303B_START_ADDRESS + i)) { continue; }
if (HP303BSensor.begin(HP303B_START_ADDRESS + i)) {
hp303b_sensor[hp303b_cfg.count].address = HP303B_START_ADDRESS + i;
I2cSetActiveFound(hp303b_sensor[hp303b_cfg.count].address, hp303b_cfg.types);
hp303b_cfg.count++;
}
}
}
void HP303B_EverySecond(void) {
for (uint32_t i = 0; i < hp303b_cfg.count; i++) {
if (uptime &1) {
if (!HP303B_Read(i)) {
AddLogMissed(hp303b_cfg.types, hp303b_sensor[i].valid);
}
}
}
}
void HP303B_Show(bool json) {
for (uint32_t i = 0; i < hp303b_cfg.count; i++) {
if (hp303b_sensor[i].valid) {
char sensor_name[12];
strlcpy(sensor_name, hp303b_cfg.types, sizeof(sensor_name));
if (hp303b_cfg.count > 1) {
snprintf_P(sensor_name, sizeof(sensor_name), PSTR("%s%c%02X"), sensor_name, IndexSeparator(), hp303b_sensor[i].address); // HP303B-76, HP303B-77
}
float sealevel = 0.0;
if (hp303b_sensor[i].pressure != 0.0) {
sealevel = (hp303b_sensor[i].pressure / FastPrecisePow(1.0 - ((float)Settings.altitude / 44330.0), 5.255)) - 21.6;
sealevel = ConvertPressure(sealevel);
}
char str_temperature[33];
dtostrfd(hp303b_sensor[i].temperature, Settings.flag2.temperature_resolution, str_temperature);
char str_pressure[33];
dtostrfd(hp303b_sensor[i].pressure, Settings.flag2.pressure_resolution, str_pressure);
char sea_pressure[33];
dtostrfd(sealevel, Settings.flag2.pressure_resolution, sea_pressure);
if (json) {
ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_PRESSURE "\":%s"), sensor_name, str_temperature, str_pressure);
if (Settings.altitude != 0) {
ResponseAppend_P(PSTR(",\"" D_JSON_PRESSUREATSEALEVEL "\":%s"), sea_pressure);
}
ResponseJsonEnd();
#ifdef USE_DOMOTICZ
// Domoticz and knx only support one temp sensor
if ((0 == tele_period) && (0 == i)) {
DomoticzSensor(DZ_TEMP, hp303b_sensor[i].temperature);
}
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
} else {
WSContentSend_PD(HTTP_SNS_TEMP, sensor_name, str_temperature, TempUnit());
WSContentSend_PD(HTTP_SNS_PRESSURE, sensor_name, str_pressure, PressureUnit().c_str());
if (Settings.altitude != 0) {
WSContentSend_PD(HTTP_SNS_SEAPRESSURE, sensor_name, sea_pressure, PressureUnit().c_str());
}
#endif // USE_WEBSERVER
}
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xsns73(uint8_t function)
{
if (!I2cEnabled(XI2C_52)) { return false; }
bool result = false;
if (FUNC_INIT == function) {
HP303B_Detect();
}
else if (hp303b_cfg.count) {
switch (function) {
case FUNC_EVERY_SECOND:
HP303B_EverySecond();
break;
case FUNC_JSON_APPEND:
HP303B_Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_WEB_SENSOR:
HP303B_Show(0);
break;
#endif // USE_WEBSERVER
}
}
return result;
}
#endif // USE_HP303B
#endif // USE_I2C

View File

@ -37,7 +37,7 @@ void HandleMetrics(void)
char parameter[FLOATSZ]; char parameter[FLOATSZ];
if (global_temperature != 9999) { if (!isnan(global_temperature)) {
dtostrfd(global_temperature, Settings.flag2.temperature_resolution, parameter); dtostrfd(global_temperature, Settings.flag2.temperature_resolution, parameter);
WSContentSend_P(PSTR("# TYPE global_temperature gauge\nglobal_temperature %s\n"), parameter); WSContentSend_P(PSTR("# TYPE global_temperature gauge\nglobal_temperature %s\n"), parameter);
} }

View File

@ -205,8 +205,8 @@ a_features = [[
"USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080", "USE_KEELOQ","USE_HRXL","USE_SONOFF_D1","USE_HDC1080",
"USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING", "USE_IAQ","USE_DISPLAY_SEVENSEG","USE_AS3935","USE_PING",
"USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075", "USE_WINDMETER","USE_OPENTHERM","USE_THERMOSTAT","USE_VEML6075",
"USE_VEML7700","USE_MCP9808","USE_BL0940","", "USE_VEML7700","USE_MCP9808","USE_BL0940","USE_TELEGRAM",
"","","","", "USE_HP303B","","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","USE_WEBCAM" "","","","USE_WEBCAM"
@ -243,7 +243,7 @@ else:
obj = json.load(fp) obj = json.load(fp)
def StartDecode(): def StartDecode():
print ("\n*** decode-status.py v20200607 by Theo Arends and Jacek Ziolkowski ***") print ("\n*** decode-status.py v20200611 by Theo Arends and Jacek Ziolkowski ***")
# print("Decoding\n{}".format(obj)) # print("Decoding\n{}".format(obj))