Merge branch 'development' into teleinfo-dev

This commit is contained in:
Charles 2020-06-19 02:37:11 +02:00
commit 8f3821d862
119 changed files with 17275 additions and 2426 deletions

View File

@ -77,6 +77,7 @@
| USE_MAX31855 | - | - | - | - | x | - | - |
| USE_MAX31865 | - | - | - | - | - | - | - |
| USE_THERMOSTAT | - | - | - | - | - | - | - |
| USE_LMT01 | - | - | - | - | x | - | - |
| | | | | | | | |
| Feature or Sensor | minimal | lite | tasmota | knx | sensors | ir | display | Remarks
| USE_I2C | - | - | x | x | x | - | x |
@ -181,3 +182,4 @@
|-----------------------|---------|-------|--------|-----|---------|----|---------|--------|--------
| USE_MI_ESP32 | - | - | - | - | - | - | - | - |
| USE_WEBCAM | - | - | - | - | - | - | - | x |
| USE_ETHERNET | - | - | - | - | - | - | - | - |

View File

@ -73,3 +73,4 @@ Index | Define | Driver | Device | Address(es) | Description
49 | USE_VEML6075 | xsns_70 | VEML6075 | 0x10 | UVA/UVB/UVINDEX Sensor
50 | USE_VEML7700 | xsns_71 | VEML7700 | 0x10 | Ambient light intensity 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,19 +52,22 @@ The following binary downloads have been compiled with ESP8266/Arduino library c
## Changelog
### Version 8.3.1.2
### Version 8.3.1.6
- 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)
- Change IRremoteESP8266 library updated to v2.7.7
- Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519)
- 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 ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]``
- Change ESP32 USER GPIO template representation decreasing template message size
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
- Fix escape of non-JSON received serial data (#8329)
- Add command ``Rule0`` to change global rule parameters
- Add command ``Time 4`` to display timestamp using milliseconds (#8537)
- Add command ``SetOption94 0/1`` to select MAX31855 or MAX6675 thermocouple support (#8616)
- Add command ``Module2`` to configure fallback module on fast reboot (#8464)
- Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491)
- Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3``
- Add support for unique MQTTClient (and inherited fallback topic) by full Mac address using ``mqttclient DVES_%12X`` (#8300)
- Add more functionality to ``Switchmode`` 11 and 12 (#8450)
- Add wildcard pattern ``?`` for JSON matching in rules
@ -78,3 +81,10 @@ 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 eight MCP9808 temperature sensors by device111 (#8594)
- 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
- Add support for 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
- Add Library to be used for decoding Teleinfo (French Metering Smart Meter)
- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)

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

@ -1,6 +1,6 @@
{
"name": "LibTeleinfo",
"version": "1.1.1",
"version": "1.1.2",
"keywords": "teleinfo, french, meter, power, erdf, linky, tic",
"description": "Decoder for Teleinfo (aka TIC) from French smart power meters",
"repository":

View File

@ -1,5 +1,5 @@
name=LibTeleinfo
version=1.1.1
version=1.1.2
author=Charles-Henri Hallard <hallard.me>
maintainer=Charles-Henri Hallard <community.hallard.me>
sentence=Decoder for Teleinfo (aka TIC) from French smart power meters

View File

@ -426,7 +426,45 @@ char * TInfo::valueGet(char * name, char * value)
if (me->value) {
// copy to dest buffer
uint8_t lgvalue = strlen(me->value);
strlcpy(value, me->value , lgvalue );
strlcpy(value, me->value , lgvalue + 1 );
return ( value );
}
}
}
}
// not found
return ( NULL);
}
/* ======================================================================
Function: valueGet_P
Purpose : get value of one element
Input : Pointer to the label name
pointer to the value where we fill data
Output : pointer to the value where we filled data NULL is not found
====================================================================== */
char * TInfo::valueGet_P(const char * name, char * value)
{
// Get our linked list
ValueList * me = &_valueslist;
uint8_t lgname = strlen_P(name);
// Got one and all seems good ?
if (me && lgname) {
// Loop thru the node
while (me->next) {
// go to next node
me = me->next;
// Check if we match this LABEL
if (lgname==strlen(me->name) && strncmp_P(me->name, name, lgname)==0) {
// this one has a value ?
if (me->value) {
// copy to dest buffer
uint8_t lgvalue = strlen(me->value);
strlcpy(value, me->value , lgvalue + 1 );
return ( value );
}
}
@ -661,7 +699,7 @@ ValueList * TInfo::checkLine(char * pline)
return NULL;
// Get our own working copy
strlcpy( buff, _recv_buff, len+1);
strlcpy( buff, pline, len+1);
p = &buff[0];
ptok = p; // for sure we start with token name

View File

@ -117,6 +117,7 @@ class TInfo
ValueList * getList(void);
uint8_t valuesDump(void);
char * valueGet(char * name, char * value);
char * valueGet_P(const char * name, char * value);
boolean listDelete();
unsigned char calcChecksum(char *etiquette, char *valeur) ;

View File

@ -398,7 +398,7 @@ typedef struct __callback_assignment
} callback_assignment_t;
// FastPrecisePowf from tasmota/support_float.ino
extern float FastPrecisePowf(const float x, const float y);
//extern float FastPrecisePowf(const float x, const float y);
class ESPKNXIP {
public:
@ -567,7 +567,7 @@ class ESPKNXIP {
callback_assignment_id_t __callback_register_assignment(address_t address, callback_id_t id);
void __callback_delete_assignment(callback_assignment_id_t id);
static inline float pow(float a, float b) { return FastPrecisePowf(a, b); }
//static inline float pow(float a, float b) { return FastPrecisePowf(a, b); }
ESP8266WebServer *server;
address_t physaddr;

1
lib/mbedtls/README.md Normal file
View File

@ -0,0 +1 @@
Stripped down library for aes-ccm-decryption in the MI_NRF24.ino.

View File

@ -0,0 +1,297 @@
/**
* \file aes.h
*
* \brief AES block cipher
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_AES_H
#define MBEDTLS_AES_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#include <stdint.h>
/* padlock.c and aesni.c rely on these values! */
#define MBEDTLS_AES_ENCRYPT 1
#define MBEDTLS_AES_DECRYPT 0
#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
#if !defined(MBEDTLS_AES_ALT)
// Regular implementation
//
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief AES context structure
*
* \note buf is able to hold 32 extra bytes, which can be used:
* - for alignment purposes if VIA padlock is used, and/or
* - to simplify key expansion in the 256-bit case by
* generating an extra round key
*/
typedef struct
{
int nr; /*!< number of rounds */
uint32_t *rk; /*!< AES round keys */
uint32_t buf[68]; /*!< unaligned data */
}
mbedtls_aes_context;
/**
* \brief Initialize AES context
*
* \param ctx AES context to be initialized
*/
void mbedtls_aes_init( mbedtls_aes_context *ctx );
/**
* \brief Clear AES context
*
* \param ctx AES context to be cleared
*/
void mbedtls_aes_free( mbedtls_aes_context *ctx );
/**
* \brief AES key schedule (encryption)
*
* \param ctx AES context to be initialized
* \param key encryption key
* \param keybits must be 128, 192 or 256
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
*/
int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits );
/**
* \brief AES key schedule (decryption)
*
* \param ctx AES context to be initialized
* \param key decryption key
* \param keybits must be 128, 192 or 256
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH
*/
int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key,
unsigned int keybits );
/**
* \brief AES-ECB block encryption/decryption
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param input 16-byte input block
* \param output 16-byte output block
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx,
int mode,
const unsigned char input[16],
unsigned char output[16] );
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/**
* \brief AES-CBC buffer encryption/decryption
* Length should be a multiple of the block
* size (16 bytes)
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH
*/
int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/**
* \brief AES-CFB128 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv_off offset in IV (updated after use)
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx,
int mode,
size_t length,
size_t *iv_off,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
/**
* \brief AES-CFB8 buffer encryption/decryption.
*
* Note: Due to the nature of CFB you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \note Upon exit, the content of the IV is updated so that you can
* call the function same function again on the following
* block(s) of data and get the same result as if it was
* encrypted in one call. This allows a "streaming" usage.
* If on the other hand you need to retain the contents of the
* IV, you should either save it manually or use the cipher
* module instead.
*
* \param ctx AES context
* \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT
* \param length length of the input data
* \param iv initialization vector (updated after use)
* \param input buffer holding the input data
* \param output buffer holding the output data
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx,
int mode,
size_t length,
unsigned char iv[16],
const unsigned char *input,
unsigned char *output );
#endif /*MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/**
* \brief AES-CTR buffer encryption/decryption
*
* Warning: You have to keep the maximum use of your counter in mind!
*
* Note: Due to the nature of CTR you should use the same key schedule for
* both encryption and decryption. So a context initialized with
* mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT.
*
* \param ctx AES context
* \param length The length of the data
* \param nc_off The offset in the current stream_block (for resuming
* within current cipher stream). The offset pointer to
* should be 0 at the start of a stream.
* \param nonce_counter The 128-bit nonce and counter.
* \param stream_block The saved stream-block for resuming. Is overwritten
* by the function.
* \param input The input data stream
* \param output The output data stream
*
* \return 0 if successful
*/
int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx,
size_t length,
size_t *nc_off,
unsigned char nonce_counter[16],
unsigned char stream_block[16],
const unsigned char *input,
unsigned char *output );
#endif /* MBEDTLS_CIPHER_MODE_CTR */
/**
* \brief Internal AES block encryption function
* (Only exposed to allow overriding it,
* see MBEDTLS_AES_ENCRYPT_ALT)
*
* \param ctx AES context
* \param input Plaintext block
* \param output Output (ciphertext) block
*/
void mbedtls_aes_encrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] );
/**
* \brief Internal AES block decryption function
* (Only exposed to allow overriding it,
* see MBEDTLS_AES_DECRYPT_ALT)
*
* \param ctx AES context
* \param input Ciphertext block
* \param output Output (plaintext) block
*/
void mbedtls_aes_decrypt( mbedtls_aes_context *ctx,
const unsigned char input[16],
unsigned char output[16] );
#ifdef __cplusplus
}
#endif
#else /* MBEDTLS_AES_ALT */
#include "aes_alt.h"
#endif /* MBEDTLS_AES_ALT */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_aes_self_test( int verbose );
#ifdef __cplusplus
}
#endif
#endif /* aes.h */

View File

@ -0,0 +1,141 @@
/**
* \file ccm.h
*
* \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CCM_H
#define MBEDTLS_CCM_H
#include "cipher.h"
#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */
#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */
#ifdef __cplusplus
extern "C" {
#endif
/**
* \brief CCM context structure
*/
typedef struct {
mbedtls_cipher_context_t cipher_ctx; /*!< cipher context used */
}
mbedtls_ccm_context;
/**
* \brief Initialize CCM context (just makes references valid)
* Makes the context ready for mbedtls_ccm_setkey() or
* mbedtls_ccm_free().
*
* \param ctx CCM context to initialize
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx );
/**
* \brief CCM initialization (encryption and decryption)
*
* \param ctx CCM context to be initialized
* \param cipher cipher to use (a 128-bit block cipher)
* \param key encryption key
* \param keybits key size in bits (must be acceptable by the cipher)
*
* \return 0 if successful, or a cipher specific error code
*/
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits );
/**
* \brief Free a CCM context and underlying cipher sub-context
*
* \param ctx CCM context to free
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx );
/**
* \brief CCM buffer encryption
*
* \param ctx CCM context
* \param length length of the input data in bytes
* \param iv nonce (initialization vector)
* \param iv_len length of IV in bytes
* must be 2, 3, 4, 5, 6, 7 or 8
* \param add additional data
* \param add_len length of additional data in bytes
* must be less than 2^16 - 2^8
* \param input buffer holding the input data
* \param output buffer for holding the output data
* must be at least 'length' bytes wide
* \param tag buffer for holding the tag
* \param tag_len length of the tag to generate in bytes
* must be 4, 6, 8, 10, 14 or 16
*
* \note The tag is written to a separate buffer. To get the tag
* concatenated with the output as in the CCM spec, use
* tag = output + length and make sure the output buffer is
* at least length + tag_len wide.
*
* \return 0 if successful
*/
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len );
/**
* \brief CCM buffer authenticated decryption
*
* \param ctx CCM context
* \param length length of the input data
* \param iv initialization vector
* \param iv_len length of IV
* \param add additional data
* \param add_len length of additional data
* \param input buffer holding the input data
* \param output buffer for holding the output data
* \param tag buffer holding the tag
* \param tag_len length of the tag
*
* \return 0 if successful and authenticated,
* MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match
*/
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len );
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
/**
* \brief Checkup routine
*
* \return 0 if successful, or 1 if the test failed
*/
int mbedtls_ccm_self_test( int verbose );
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_CCM_H */

View File

@ -0,0 +1,628 @@
/**
* \file check_config.h
*
* \brief Consistency checks for configuration options
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* It is recommended to include this file from your config.h
* in order to catch dependency issues early.
*/
#ifndef MBEDTLS_CHECK_CONFIG_H
#define MBEDTLS_CHECK_CONFIG_H
/*
* We assume CHAR_BIT is 8 in many places. In practice, this is true on our
* target platforms, so not an issue, but let's just be extra sure.
*/
#include <limits.h>
#if CHAR_BIT != 8
#error "mbed TLS requires a platform with 8-bit chars"
#endif
#if defined(_WIN32)
#if !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_C is required on Windows"
#endif
/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as
* it would confuse config.pl. */
#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \
!defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define MBEDTLS_PLATFORM_SNPRINTF_ALT
#endif
#endif /* _WIN32 */
#if defined(TARGET_LIKE_MBED) && \
( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) )
#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS"
#endif
#if defined(MBEDTLS_DEPRECATED_WARNING) && \
!defined(__GNUC__) && !defined(__clang__)
#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang"
#endif
#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME)
#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense"
#endif
#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_AESNI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C)
#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C)
#error "MBEDTLS_DHM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_CMAC_C) && \
!defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C)
#error "MBEDTLS_CMAC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C)
#error "MBEDTLS_ECDH_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDSA_C) && \
( !defined(MBEDTLS_ECP_C) || \
!defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_ASN1_WRITE_C) )
#error "MBEDTLS_ECDSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECJPAKE_C) && \
( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) )
#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C)
#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \
!defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \
!defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) )
#error "MBEDTLS_ECP_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \
!defined(MBEDTLS_SHA256_C))
#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \
defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \
&& defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32)
#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high"
#endif
#if defined(MBEDTLS_ENTROPY_C) && \
defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C)
#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) )
#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \
( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \
defined(MBEDTLS_HAVEGE_C) )
#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too"
#endif
#if defined(MBEDTLS_GCM_C) && ( \
!defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) )
#error "MBEDTLS_GCM_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C)
#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C)
#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C)
#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \
!defined(MBEDTLS_ECDH_C)
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \
( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \
( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \
!defined(MBEDTLS_X509_CRT_PARSE_C) )
#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \
( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \
!defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) )
#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM)
#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C)
#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_C) && \
( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) )
#error "MBEDTLS_PK_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C)
#error "MBEDTLS_PKCS11_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\
defined(MBEDTLS_PLATFORM_EXIT_ALT) )
#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_TIME) ||\
defined(MBEDTLS_PLATFORM_TIME_ALT) )
#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\
defined(MBEDTLS_PLATFORM_FPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_FREE)
#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) )
#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\
defined(MBEDTLS_PLATFORM_STD_CALLOC)
#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO)
#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is"
#endif
#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\
defined(MBEDTLS_PLATFORM_PRINTF_ALT) )
#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C)
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\
defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) )
#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\
!defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY)
#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\
!defined(MBEDTLS_PLATFORM_EXIT_ALT)
#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\
( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\
!defined(MBEDTLS_HAVE_TIME) )
#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\
!defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\
!defined(MBEDTLS_PLATFORM_PRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\
!defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\
( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) )
#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\
!defined(MBEDTLS_ENTROPY_NV_SEED)
#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\
!defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\
( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\
defined(MBEDTLS_PLATFORM_NV_SEED_ALT) )
#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) )
#error "MBEDTLS_RSA_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \
!defined(MBEDTLS_PKCS1_V15) )
#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled"
#endif
#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \
( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) )
#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \
!defined(MBEDTLS_SHA1_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \
!defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) )
#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_PROTO_DTLS) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \
!defined(MBEDTLS_MD_C) )
#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C)
#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2))
#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \
defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \
!defined(MBEDTLS_SSL_PROTO_TLS1_1)))
#error "Illegal protocol selection"
#endif
#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS)
#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \
!defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY)
#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \
( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) )
#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \
!defined(MBEDTLS_SSL_PROTO_TLS1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_1) && \
!defined(MBEDTLS_SSL_PROTO_TLS1_2)
#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites"
#endif
#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C)
#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \
!defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1)
#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \
!defined(MBEDTLS_X509_CRT_PARSE_C)
#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_THREADING_PTHREAD)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_ALT)
#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites"
#endif
#define MBEDTLS_THREADING_IMPL
#endif
#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL)
#error "MBEDTLS_THREADING_C defined, single threading implementation required"
#endif
#undef MBEDTLS_THREADING_IMPL
#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C)
#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \
!defined(MBEDTLS_PK_PARSE_C) )
#error "MBEDTLS_X509_USE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \
!defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \
!defined(MBEDTLS_PK_WRITE_C) )
#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) )
#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites"
#endif
#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) )
#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites"
#endif
/*
* Avoid warning from -pedantic. This is a convenient place for this
* workaround since this is included by every single file before the
* #if defined(MBEDTLS_xxx_C) that results in emtpy translation units.
*/
typedef int mbedtls_iso_c_forbids_empty_translation_units;
#endif /* MBEDTLS_CHECK_CONFIG_H */

View File

@ -0,0 +1,709 @@
/**
* \file cipher.h
*
* \brief Generic cipher wrapper.
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CIPHER_H
#define MBEDTLS_CIPHER_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include <stddef.h>
#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)
#define MBEDTLS_CIPHER_MODE_AEAD
#endif
#if defined(MBEDTLS_CIPHER_MODE_CBC)
#define MBEDTLS_CIPHER_MODE_WITH_PADDING
#endif
#if defined(MBEDTLS_ARC4_C)
#define MBEDTLS_CIPHER_MODE_STREAM
#endif
#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
!defined(inline) && !defined(__cplusplus)
#define inline __inline
#endif
#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */
#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */
#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */
#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */
#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */
#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */
#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid, eg because it was free()ed. */
#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length */
#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length */
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
MBEDTLS_CIPHER_ID_NONE = 0,
MBEDTLS_CIPHER_ID_NULL,
MBEDTLS_CIPHER_ID_AES,
MBEDTLS_CIPHER_ID_DES,
MBEDTLS_CIPHER_ID_3DES,
MBEDTLS_CIPHER_ID_CAMELLIA,
MBEDTLS_CIPHER_ID_BLOWFISH,
MBEDTLS_CIPHER_ID_ARC4,
} mbedtls_cipher_id_t;
typedef enum {
MBEDTLS_CIPHER_NONE = 0,
MBEDTLS_CIPHER_NULL,
MBEDTLS_CIPHER_AES_128_ECB,
MBEDTLS_CIPHER_AES_192_ECB,
MBEDTLS_CIPHER_AES_256_ECB,
MBEDTLS_CIPHER_AES_128_CBC,
MBEDTLS_CIPHER_AES_192_CBC,
MBEDTLS_CIPHER_AES_256_CBC,
MBEDTLS_CIPHER_AES_128_CFB128,
MBEDTLS_CIPHER_AES_192_CFB128,
MBEDTLS_CIPHER_AES_256_CFB128,
MBEDTLS_CIPHER_AES_128_CTR,
MBEDTLS_CIPHER_AES_192_CTR,
MBEDTLS_CIPHER_AES_256_CTR,
MBEDTLS_CIPHER_AES_128_GCM,
MBEDTLS_CIPHER_AES_192_GCM,
MBEDTLS_CIPHER_AES_256_GCM,
MBEDTLS_CIPHER_CAMELLIA_128_ECB,
MBEDTLS_CIPHER_CAMELLIA_192_ECB,
MBEDTLS_CIPHER_CAMELLIA_256_ECB,
MBEDTLS_CIPHER_CAMELLIA_128_CBC,
MBEDTLS_CIPHER_CAMELLIA_192_CBC,
MBEDTLS_CIPHER_CAMELLIA_256_CBC,
MBEDTLS_CIPHER_CAMELLIA_128_CFB128,
MBEDTLS_CIPHER_CAMELLIA_192_CFB128,
MBEDTLS_CIPHER_CAMELLIA_256_CFB128,
MBEDTLS_CIPHER_CAMELLIA_128_CTR,
MBEDTLS_CIPHER_CAMELLIA_192_CTR,
MBEDTLS_CIPHER_CAMELLIA_256_CTR,
MBEDTLS_CIPHER_CAMELLIA_128_GCM,
MBEDTLS_CIPHER_CAMELLIA_192_GCM,
MBEDTLS_CIPHER_CAMELLIA_256_GCM,
MBEDTLS_CIPHER_DES_ECB,
MBEDTLS_CIPHER_DES_CBC,
MBEDTLS_CIPHER_DES_EDE_ECB,
MBEDTLS_CIPHER_DES_EDE_CBC,
MBEDTLS_CIPHER_DES_EDE3_ECB,
MBEDTLS_CIPHER_DES_EDE3_CBC,
MBEDTLS_CIPHER_BLOWFISH_ECB,
MBEDTLS_CIPHER_BLOWFISH_CBC,
MBEDTLS_CIPHER_BLOWFISH_CFB64,
MBEDTLS_CIPHER_BLOWFISH_CTR,
MBEDTLS_CIPHER_ARC4_128,
MBEDTLS_CIPHER_AES_128_CCM,
MBEDTLS_CIPHER_AES_192_CCM,
MBEDTLS_CIPHER_AES_256_CCM,
MBEDTLS_CIPHER_CAMELLIA_128_CCM,
MBEDTLS_CIPHER_CAMELLIA_192_CCM,
MBEDTLS_CIPHER_CAMELLIA_256_CCM,
} mbedtls_cipher_type_t;
typedef enum {
MBEDTLS_MODE_NONE = 0,
MBEDTLS_MODE_ECB,
MBEDTLS_MODE_CBC,
MBEDTLS_MODE_CFB,
MBEDTLS_MODE_OFB, /* Unused! */
MBEDTLS_MODE_CTR,
MBEDTLS_MODE_GCM,
MBEDTLS_MODE_STREAM,
MBEDTLS_MODE_CCM,
} mbedtls_cipher_mode_t;
typedef enum {
MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default) */
MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding */
MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding */
MBEDTLS_PADDING_ZEROS, /**< zero padding (not reversible!) */
MBEDTLS_PADDING_NONE, /**< never pad (full blocks only) */
} mbedtls_cipher_padding_t;
typedef enum {
MBEDTLS_OPERATION_NONE = -1,
MBEDTLS_DECRYPT = 0,
MBEDTLS_ENCRYPT,
} mbedtls_operation_t;
enum {
/** Undefined key length */
MBEDTLS_KEY_LENGTH_NONE = 0,
/** Key length, in bits (including parity), for DES keys */
MBEDTLS_KEY_LENGTH_DES = 64,
/** Key length, in bits (including parity), for DES in two key EDE */
MBEDTLS_KEY_LENGTH_DES_EDE = 128,
/** Key length, in bits (including parity), for DES in three-key EDE */
MBEDTLS_KEY_LENGTH_DES_EDE3 = 192,
};
/** Maximum length of any IV, in bytes */
#define MBEDTLS_MAX_IV_LENGTH 16
/** Maximum block size of any cipher, in bytes */
#define MBEDTLS_MAX_BLOCK_LENGTH 16
/**
* Base cipher information (opaque struct).
*/
typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t;
/**
* CMAC context (opaque struct).
*/
typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t;
/**
* Cipher information. Allows cipher functions to be called in a generic way.
*/
typedef struct {
/** Full cipher identifier (e.g. MBEDTLS_CIPHER_AES_256_CBC) */
mbedtls_cipher_type_t type;
/** Cipher mode (e.g. MBEDTLS_MODE_CBC) */
mbedtls_cipher_mode_t mode;
/** Cipher key length, in bits (default length for variable sized ciphers)
* (Includes parity bits for ciphers like DES) */
unsigned int key_bitlen;
/** Name of the cipher */
const char * name;
/** IV/NONCE size, in bytes.
* For cipher that accept many sizes: recommended size */
unsigned int iv_size;
/** Flags for variable IV size, variable key size, etc. */
int flags;
/** block size, in bytes */
unsigned int block_size;
/** Base cipher information and functions */
const mbedtls_cipher_base_t *base;
} mbedtls_cipher_info_t;
/**
* Generic cipher context.
*/
typedef struct {
/** Information about the associated cipher */
const mbedtls_cipher_info_t *cipher_info;
/** Key length to use */
int key_bitlen;
/** Operation that the context's key has been initialised for */
mbedtls_operation_t operation;
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
/** Padding functions to use, if relevant for cipher mode */
void (*add_padding)( unsigned char *output, size_t olen, size_t data_len );
int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len );
#endif
/** Buffer for data that hasn't been encrypted yet */
unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH];
/** Number of bytes that still need processing */
size_t unprocessed_len;
/** Current IV or NONCE_COUNTER for CTR-mode */
unsigned char iv[MBEDTLS_MAX_IV_LENGTH];
/** IV size in bytes (for ciphers with variable-length IVs) */
size_t iv_size;
/** Cipher-specific context */
void *cipher_ctx;
#if defined(MBEDTLS_CMAC_C)
/** CMAC Specific context */
mbedtls_cmac_context_t *cmac_ctx;
#endif
} mbedtls_cipher_context_t;
/**
* \brief Returns the list of ciphers supported by the generic cipher module.
*
* \return a statically allocated array of ciphers, the last entry
* is 0.
*/
const int *mbedtls_cipher_list( void );
/**
* \brief Returns the cipher information structure associated
* with the given cipher name.
*
* \param cipher_name Name of the cipher to search for.
*
* \return the cipher information structure associated with the
* given cipher_name, or NULL if not found.
*/
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name );
/**
* \brief Returns the cipher information structure associated
* with the given cipher type.
*
* \param cipher_type Type of the cipher to search for.
*
* \return the cipher information structure associated with the
* given cipher_type, or NULL if not found.
*/
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type );
/**
* \brief Returns the cipher information structure associated
* with the given cipher id, key size and mode.
*
* \param cipher_id Id of the cipher to search for
* (e.g. MBEDTLS_CIPHER_ID_AES)
* \param key_bitlen Length of the key in bits
* \param mode Cipher mode (e.g. MBEDTLS_MODE_CBC)
*
* \return the cipher information structure associated with the
* given cipher_type, or NULL if not found.
*/
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
int key_bitlen,
const mbedtls_cipher_mode_t mode );
/**
* \brief Initialize a cipher_context (as NONE)
*/
void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx );
/**
* \brief Free and clear the cipher-specific context of ctx.
* Freeing ctx itself remains the responsibility of the
* caller.
*/
void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx );
/**
* \brief Initialises and fills the cipher context structure with
* the appropriate values.
*
* \note Currently also clears structure. In future versions you
* will be required to call mbedtls_cipher_init() on the structure
* first.
*
* \param ctx context to initialise. May not be NULL.
* \param cipher_info cipher to use.
*
* \return 0 on success,
* MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure,
* MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the
* cipher-specific context failed.
*/
int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info );
/**
* \brief Returns the block size of the given cipher.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return size of the cipher's blocks, or 0 if ctx has not been
* initialised.
*/
static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return 0;
return ctx->cipher_info->block_size;
}
/**
* \brief Returns the mode of operation for the cipher.
* (e.g. MBEDTLS_MODE_CBC)
*
* \param ctx cipher's context. Must have been initialised.
*
* \return mode of operation, or MBEDTLS_MODE_NONE if ctx
* has not been initialised.
*/
static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return MBEDTLS_MODE_NONE;
return ctx->cipher_info->mode;
}
/**
* \brief Returns the size of the cipher's IV/NONCE in bytes.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return If IV has not been set yet: (recommended) IV size
* (0 for ciphers not using IV/NONCE).
* If IV has already been set: actual size.
*/
static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return 0;
if( ctx->iv_size != 0 )
return (int) ctx->iv_size;
return (int) ctx->cipher_info->iv_size;
}
/**
* \brief Returns the type of the given cipher.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return type of the cipher, or MBEDTLS_CIPHER_NONE if ctx has
* not been initialised.
*/
static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return MBEDTLS_CIPHER_NONE;
return ctx->cipher_info->type;
}
/**
* \brief Returns the name of the given cipher, as a string.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return name of the cipher, or NULL if ctx was not initialised.
*/
static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return 0;
return ctx->cipher_info->name;
}
/**
* \brief Returns the key length of the cipher.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return cipher's key length, in bits, or
* MBEDTLS_KEY_LENGTH_NONE if ctx has not been
* initialised.
*/
static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return MBEDTLS_KEY_LENGTH_NONE;
return (int) ctx->cipher_info->key_bitlen;
}
/**
* \brief Returns the operation of the given cipher.
*
* \param ctx cipher's context. Must have been initialised.
*
* \return operation (MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT),
* or MBEDTLS_OPERATION_NONE if ctx has not been
* initialised.
*/
static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return MBEDTLS_OPERATION_NONE;
return ctx->operation;
}
/**
* \brief Set the key to use with the given context.
*
* \param ctx generic cipher context. May not be NULL. Must have been
* initialised using cipher_context_from_type or
* cipher_context_from_string.
* \param key The key to use.
* \param key_bitlen key length to use, in bits.
* \param operation Operation that the key will be used for, either
* MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT.
*
* \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
* parameter verification fails or a cipher specific
* error code.
*/
int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
int key_bitlen, const mbedtls_operation_t operation );
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
/**
* \brief Set padding mode, for cipher modes that use padding.
* (Default: PKCS7 padding.)
*
* \param ctx generic cipher context
* \param mode padding mode
*
* \returns 0 on success, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE
* if selected padding mode is not supported, or
* MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode
* does not support padding.
*/
int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode );
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
/**
* \brief Set the initialization vector (IV) or nonce
*
* \param ctx generic cipher context
* \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
* \param iv_len IV length for ciphers with variable-size IV;
* discarded by ciphers with fixed-size IV.
*
* \returns 0 on success, or MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
*
* \note Some ciphers don't use IVs nor NONCE. For these
* ciphers, this function has no effect.
*/
int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len );
/**
* \brief Finish preparation of the given context
*
* \param ctx generic cipher context
*
* \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA
* if parameter verification fails.
*/
int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx );
#if defined(MBEDTLS_GCM_C)
/**
* \brief Add additional data (for AEAD ciphers).
* Currently only supported with GCM.
* Must be called exactly once, after mbedtls_cipher_reset().
*
* \param ctx generic cipher context
* \param ad Additional data to use.
* \param ad_len Length of ad.
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
const unsigned char *ad, size_t ad_len );
#endif /* MBEDTLS_GCM_C */
/**
* \brief Generic cipher update function. Encrypts/decrypts
* using the given cipher context. Writes as many block
* size'd blocks of data as possible to output. Any data
* that cannot be written immediately will either be added
* to the next block, or flushed when cipher_final is
* called.
* Exception: for MBEDTLS_MODE_ECB, expects single block
* in size (e.g. 16 bytes for AES)
*
* \param ctx generic cipher context
* \param input buffer holding the input data
* \param ilen length of the input data
* \param output buffer for the output data. Should be able to hold at
* least ilen + block_size. Cannot be the same buffer as
* input!
* \param olen length of the output data, will be filled with the
* actual number of bytes written.
*
* \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
* parameter verification fails,
* MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an
* unsupported mode for a cipher or a cipher specific
* error code.
*
* \note If the underlying cipher is GCM, all calls to this
* function, except the last one before mbedtls_cipher_finish(),
* must have ilen a multiple of the block size.
*/
int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
size_t ilen, unsigned char *output, size_t *olen );
/**
* \brief Generic cipher finalisation function. If data still
* needs to be flushed from an incomplete block, data
* contained within it will be padded with the size of
* the last block, and written to the output buffer.
*
* \param ctx Generic cipher context
* \param output buffer to write data to. Needs block_size available.
* \param olen length of the data written to the output buffer.
*
* \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if
* parameter verification fails,
* MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption
* expected a full block but was not provided one,
* MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding
* while decrypting or a cipher specific error code.
*/
int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
unsigned char *output, size_t *olen );
#if defined(MBEDTLS_GCM_C)
/**
* \brief Write tag for AEAD ciphers.
* Currently only supported with GCM.
* Must be called after mbedtls_cipher_finish().
*
* \param ctx Generic cipher context
* \param tag buffer to write the tag
* \param tag_len Length of the tag to write
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
unsigned char *tag, size_t tag_len );
/**
* \brief Check tag for AEAD ciphers.
* Currently only supported with GCM.
* Must be called after mbedtls_cipher_finish().
*
* \param ctx Generic cipher context
* \param tag Buffer holding the tag
* \param tag_len Length of the tag to check
*
* \return 0 on success, or a specific error code.
*/
int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
const unsigned char *tag, size_t tag_len );
#endif /* MBEDTLS_GCM_C */
/**
* \brief Generic all-in-one encryption/decryption
* (for all ciphers except AEAD constructs).
*
* \param ctx generic cipher context
* \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
* \param iv_len IV length for ciphers with variable-size IV;
* discarded by ciphers with fixed-size IV.
* \param input buffer holding the input data
* \param ilen length of the input data
* \param output buffer for the output data. Should be able to hold at
* least ilen + block_size. Cannot be the same buffer as
* input!
* \param olen length of the output data, will be filled with the
* actual number of bytes written.
*
* \note Some ciphers don't use IVs nor NONCE. For these
* ciphers, use iv = NULL and iv_len = 0.
*
* \returns 0 on success, or
* MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
* MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption
* expected a full block but was not provided one, or
* MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding
* while decrypting, or
* a cipher specific error code.
*/
int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen );
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
/**
* \brief Generic autenticated encryption (AEAD ciphers).
*
* \param ctx generic cipher context
* \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
* \param iv_len IV length for ciphers with variable-size IV;
* discarded by ciphers with fixed-size IV.
* \param ad Additional data to authenticate.
* \param ad_len Length of ad.
* \param input buffer holding the input data
* \param ilen length of the input data
* \param output buffer for the output data.
* Should be able to hold at least ilen.
* \param olen length of the output data, will be filled with the
* actual number of bytes written.
* \param tag buffer for the authentication tag
* \param tag_len desired tag length
*
* \returns 0 on success, or
* MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
* a cipher specific error code.
*/
int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
unsigned char *tag, size_t tag_len );
/**
* \brief Generic autenticated decryption (AEAD ciphers).
*
* \param ctx generic cipher context
* \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers)
* \param iv_len IV length for ciphers with variable-size IV;
* discarded by ciphers with fixed-size IV.
* \param ad Additional data to be authenticated.
* \param ad_len Length of ad.
* \param input buffer holding the input data
* \param ilen length of the input data
* \param output buffer for the output data.
* Should be able to hold at least ilen.
* \param olen length of the output data, will be filled with the
* actual number of bytes written.
* \param tag buffer holding the authentication tag
* \param tag_len length of the authentication tag
*
* \returns 0 on success, or
* MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or
* MBEDTLS_ERR_CIPHER_AUTH_FAILED if data isn't authentic,
* or a cipher specific error code.
*
* \note If the data is not authentic, then the output buffer
* is zeroed out to prevent the unauthentic plaintext to
* be used by mistake, making this interface safer.
*/
int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
const unsigned char *tag, size_t tag_len );
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_CIPHER_H */

View File

@ -0,0 +1,109 @@
/**
* \file cipher_internal.h
*
* \brief Cipher wrappers.
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_CIPHER_WRAP_H
#define MBEDTLS_CIPHER_WRAP_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#include "cipher.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* Base cipher information. The non-mode specific functions and values.
*/
struct mbedtls_cipher_base_t
{
/** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */
mbedtls_cipher_id_t cipher;
/** Encrypt using ECB */
int (*ecb_func)( void *ctx, mbedtls_operation_t mode,
const unsigned char *input, unsigned char *output );
#if defined(MBEDTLS_CIPHER_MODE_CBC)
/** Encrypt using CBC */
int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length,
unsigned char *iv, const unsigned char *input,
unsigned char *output );
#endif
#if defined(MBEDTLS_CIPHER_MODE_CFB)
/** Encrypt using CFB (Full length) */
int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off,
unsigned char *iv, const unsigned char *input,
unsigned char *output );
#endif
#if defined(MBEDTLS_CIPHER_MODE_CTR)
/** Encrypt using CTR */
int (*ctr_func)( void *ctx, size_t length, size_t *nc_off,
unsigned char *nonce_counter, unsigned char *stream_block,
const unsigned char *input, unsigned char *output );
#endif
#if defined(MBEDTLS_CIPHER_MODE_STREAM)
/** Encrypt using STREAM */
int (*stream_func)( void *ctx, size_t length,
const unsigned char *input, unsigned char *output );
#endif
/** Set key for encryption purposes */
int (*setkey_enc_func)( void *ctx, const unsigned char *key,
unsigned int key_bitlen );
/** Set key for decryption purposes */
int (*setkey_dec_func)( void *ctx, const unsigned char *key,
unsigned int key_bitlen);
/** Allocate a new context */
void * (*ctx_alloc_func)( void );
/** Free the given context */
void (*ctx_free_func)( void *ctx );
};
typedef struct
{
mbedtls_cipher_type_t type;
const mbedtls_cipher_info_t *info;
} mbedtls_cipher_definition_t;
extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[];
extern int mbedtls_cipher_supported[];
#ifdef __cplusplus
}
#endif
#endif /* MBEDTLS_CIPHER_WRAP_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,295 @@
/**
* \file platform.h
*
* \brief mbed TLS Platform abstraction layer
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PLATFORM_H
#define MBEDTLS_PLATFORM_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_HAVE_TIME)
#include "mbedtls/platform_time.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h or define them on the compiler command line.
* \{
*/
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF)
#if defined(_WIN32)
#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */
#else
#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use */
#endif
#endif
#if !defined(MBEDTLS_PLATFORM_STD_PRINTF)
#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF)
#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_CALLOC)
#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_FREE)
#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT)
#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_TIME)
#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< Default exit value to use */
#endif
#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< Default exit value to use */
#endif
#if defined(MBEDTLS_FS_IO)
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ)
#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read
#endif
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE)
#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write
#endif
#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE)
#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile"
#endif
#endif /* MBEDTLS_FS_IO */
#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR)
#include MBEDTLS_PLATFORM_STD_MEM_HDR
#endif
#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */
/* \} name SECTION: Module settings */
/*
* The function pointers for calloc and free
*/
#if defined(MBEDTLS_PLATFORM_MEMORY)
#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \
defined(MBEDTLS_PLATFORM_CALLOC_MACRO)
#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO
#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO
#else
/* For size_t */
#include <stddef.h>
extern void * (*mbedtls_calloc)( size_t n, size_t size );
extern void (*mbedtls_free)( void *ptr );
/**
* \brief Set your own memory implementation function pointers
*
* \param calloc_func the calloc function implementation
* \param free_func the free function implementation
*
* \return 0 if successful
*/
int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ),
void (*free_func)( void * ) );
#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */
#else /* !MBEDTLS_PLATFORM_MEMORY */
#define mbedtls_free free
#define mbedtls_calloc calloc
#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */
/*
* The function pointers for fprintf
*/
#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT)
/* We need FILE * */
#include <stdio.h>
extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... );
/**
* \brief Set your own fprintf function pointer
*
* \param fprintf_func the fprintf function implementation
*
* \return 0
*/
int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *,
... ) );
#else
#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO)
#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO
#else
#define mbedtls_fprintf fprintf
#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */
/*
* The function pointers for printf
*/
#if defined(MBEDTLS_PLATFORM_PRINTF_ALT)
extern int (*mbedtls_printf)( const char *format, ... );
/**
* \brief Set your own printf function pointer
*
* \param printf_func the printf function implementation
*
* \return 0
*/
int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) );
#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO)
#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO
#else
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */
/*
* The function pointers for snprintf
*
* The snprintf implementation should conform to C99:
* - it *must* always correctly zero-terminate the buffer
* (except when n == 0, then it must leave the buffer untouched)
* - however it is acceptable to return -1 instead of the required length when
* the destination buffer is too short.
*/
#if defined(_WIN32)
/* For Windows (inc. MSYS2), we provide our own fixed implementation */
int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... );
#endif
#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT)
extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... );
/**
* \brief Set your own snprintf function pointer
*
* \param snprintf_func the snprintf function implementation
*
* \return 0
*/
int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n,
const char * format, ... ) );
#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO)
#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO
#else
#define mbedtls_snprintf snprintf
#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */
#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */
/*
* The function pointers for exit
*/
#if defined(MBEDTLS_PLATFORM_EXIT_ALT)
extern void (*mbedtls_exit)( int status );
/**
* \brief Set your own exit function pointer
*
* \param exit_func the exit function implementation
*
* \return 0
*/
int mbedtls_platform_set_exit( void (*exit_func)( int status ) );
#else
#if defined(MBEDTLS_PLATFORM_EXIT_MACRO)
#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO
#else
#define mbedtls_exit exit
#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */
#endif /* MBEDTLS_PLATFORM_EXIT_ALT */
/*
* The default exit values
*/
#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS)
#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS
#else
#define MBEDTLS_EXIT_SUCCESS 0
#endif
#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE)
#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE
#else
#define MBEDTLS_EXIT_FAILURE 1
#endif
/*
* The function pointers for reading from and writing a seed file to
* Non-Volatile storage (NV) in a platform-independent way
*
* Only enabled when the NV seed entropy source is enabled
*/
#if defined(MBEDTLS_ENTROPY_NV_SEED)
#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO)
/* Internal standard platform definitions */
int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len );
int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len );
#endif
#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT)
extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len );
extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len );
/**
* \brief Set your own seed file writing/reading functions
*
* \param nv_seed_read_func the seed reading function implementation
* \param nv_seed_write_func the seed writing function implementation
*
* \return 0
*/
int mbedtls_platform_set_nv_seed(
int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ),
int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len )
);
#else
#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \
defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO)
#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO
#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO
#else
#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read
#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write
#endif
#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */
#endif /* MBEDTLS_ENTROPY_NV_SEED */
#ifdef __cplusplus
}
#endif
#endif /* platform.h */

View File

@ -0,0 +1,81 @@
/**
* \file platform_time.h
*
* \brief mbed TLS Platform time abstraction
*
* Copyright (C) 2006-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#ifndef MBEDTLS_PLATFORM_TIME_H
#define MBEDTLS_PLATFORM_TIME_H
#if !defined(MBEDTLS_CONFIG_FILE)
#include "config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#ifdef __cplusplus
extern "C" {
#endif
/**
* \name SECTION: Module settings
*
* The configuration options you can set for this module are in this section.
* Either change them in config.h or define them on the compiler command line.
* \{
*/
/*
* The time_t datatype
*/
#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO)
typedef MBEDTLS_PLATFORM_TIME_TYPE_MACRO mbedtls_time_t;
#else
/* For time_t */
#include <time.h>
typedef time_t mbedtls_time_t;
#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */
/*
* The function pointers for time
*/
#if defined(MBEDTLS_PLATFORM_TIME_ALT)
extern mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* time );
/**
* \brief Set your own time function pointer
*
* \param time_func the time function implementation
*
* \return 0
*/
int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time ) );
#else
#if defined(MBEDTLS_PLATFORM_TIME_MACRO)
#define mbedtls_time MBEDTLS_PLATFORM_TIME_MACRO
#else
#define mbedtls_time time
#endif /* MBEDTLS_PLATFORM_TIME_MACRO */
#endif /* MBEDTLS_PLATFORM_TIME_ALT */
#ifdef __cplusplus
}
#endif
#endif /* platform_time.h */

1492
lib/mbedtls/src/aes.c Normal file

File diff suppressed because it is too large Load Diff

464
lib/mbedtls/src/ccm.c Normal file
View File

@ -0,0 +1,464 @@
/*
* NIST SP800-38C compliant CCM implementation
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* Definition of CCM:
* http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf
* RFC 3610 "Counter with CBC-MAC (CCM)"
*
* Related:
* RFC 5116 "An Interface and Algorithms for Authenticated Encryption"
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#include <string.h>
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_printf printf
#endif /* MBEDTLS_PLATFORM_C */
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
}
#define CCM_ENCRYPT 0
#define CCM_DECRYPT 1
/*
* Initialize context
*/
void mbedtls_ccm_init( mbedtls_ccm_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ccm_context ) );
}
int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx,
mbedtls_cipher_id_t cipher,
const unsigned char *key,
unsigned int keybits )
{
int ret;
const mbedtls_cipher_info_t *cipher_info;
cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB );
if( cipher_info == NULL )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( cipher_info->block_size != 16 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
mbedtls_cipher_free( &ctx->cipher_ctx );
if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits,
MBEDTLS_ENCRYPT ) ) != 0 )
{
return( ret );
}
return( 0 );
}
/*
* Free context
*/
void mbedtls_ccm_free( mbedtls_ccm_context *ctx )
{
mbedtls_cipher_free( &ctx->cipher_ctx );
mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) );
}
/*
* Macros for common operations.
* Results in smaller compiled code than static inline functions.
*/
/*
* Update the CBC-MAC state in y using a block in b
* (Always using b as the source helps the compiler optimise a bit better.)
*/
#define UPDATE_CBC_MAC \
for( i = 0; i < 16; i++ ) \
y[i] ^= b[i]; \
\
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \
return( ret );
/*
* Encrypt or decrypt a partial block with CTR
* Warning: using b for temporary storage! src and dst must not be b!
* This avoids allocating one more 16 bytes buffer while allowing src == dst.
*/
#define CTR_CRYPT( dst, src, len ) \
if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \
return( ret ); \
\
for( i = 0; i < len; i++ ) \
dst[i] = src[i] ^ b[i];
/*
* Authenticated encryption or decryption
*/
static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
int ret;
unsigned char i;
unsigned char q;
size_t len_left, olen;
unsigned char b[16];
unsigned char y[16];
unsigned char ctr[16];
const unsigned char *src;
unsigned char *dst;
/*
* Check length requirements: SP800-38C A.1
* Additional requirement: a < 2^16 - 2^8 to simplify the code.
* 'length' checked later (when writing it to the first block)
*/
if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Also implies q is within bounds */
if( iv_len < 7 || iv_len > 13 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
if( add_len > 0xFF00 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
q = 16 - 1 - (unsigned char) iv_len;
/*
* First block B_0:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 length
*
* With flags as (bits):
* 7 0
* 6 add present?
* 5 .. 3 (t - 2) / 2
* 2 .. 0 q - 1
*/
b[0] = 0;
b[0] |= ( add_len > 0 ) << 6;
b[0] |= ( ( tag_len - 2 ) / 2 ) << 3;
b[0] |= q - 1;
memcpy( b + 1, iv, iv_len );
for( i = 0, len_left = length; i < q; i++, len_left >>= 8 )
b[15-i] = (unsigned char)( len_left & 0xFF );
if( len_left > 0 )
return( MBEDTLS_ERR_CCM_BAD_INPUT );
/* Start CBC-MAC with first block */
memset( y, 0, 16 );
UPDATE_CBC_MAC;
/*
* If there is additional data, update CBC-MAC with
* add_len, add, 0 (padding to a block boundary)
*/
if( add_len > 0 )
{
size_t use_len;
len_left = add_len;
src = add;
memset( b, 0, 16 );
b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF );
b[1] = (unsigned char)( ( add_len ) & 0xFF );
use_len = len_left < 16 - 2 ? len_left : 16 - 2;
memcpy( b + 2, src, use_len );
len_left -= use_len;
src += use_len;
UPDATE_CBC_MAC;
while( len_left > 0 )
{
use_len = len_left > 16 ? 16 : len_left;
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
len_left -= use_len;
src += use_len;
}
}
/*
* Prepare counter block for encryption:
* 0 .. 0 flags
* 1 .. iv_len nonce (aka iv)
* iv_len+1 .. 15 counter (initially 1)
*
* With flags as (bits):
* 7 .. 3 0
* 2 .. 0 q - 1
*/
ctr[0] = q - 1;
memcpy( ctr + 1, iv, iv_len );
memset( ctr + 1 + iv_len, 0, q );
ctr[15] = 1;
/*
* Authenticate and {en,de}crypt the message.
*
* The only difference between encryption and decryption is
* the respective order of authentication and {en,de}cryption.
*/
len_left = length;
src = input;
dst = output;
while( len_left > 0 )
{
size_t use_len = len_left > 16 ? 16 : len_left;
if( mode == CCM_ENCRYPT )
{
memset( b, 0, 16 );
memcpy( b, src, use_len );
UPDATE_CBC_MAC;
}
CTR_CRYPT( dst, src, use_len );
if( mode == CCM_DECRYPT )
{
memset( b, 0, 16 );
memcpy( b, dst, use_len );
UPDATE_CBC_MAC;
}
dst += use_len;
src += use_len;
len_left -= use_len;
/*
* Increment counter.
* No need to check for overflow thanks to the length check above.
*/
for( i = 0; i < q; i++ )
if( ++ctr[15-i] != 0 )
break;
}
/*
* Authentication: reset counter and crypt/mask internal tag
*/
for( i = 0; i < q; i++ )
ctr[15-i] = 0;
CTR_CRYPT( y, y, 16 );
memcpy( tag, y, tag_len );
return( 0 );
}
/*
* Authenticated encryption
*/
int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
unsigned char *tag, size_t tag_len )
{
return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len,
add, add_len, input, output, tag, tag_len ) );
}
/*
* Authenticated decryption
*/
int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length,
const unsigned char *iv, size_t iv_len,
const unsigned char *add, size_t add_len,
const unsigned char *input, unsigned char *output,
const unsigned char *tag, size_t tag_len )
{
int ret;
unsigned char check_tag[16];
unsigned char i;
int diff;
if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length,
iv, iv_len, add, add_len,
input, output, check_tag, tag_len ) ) != 0 )
{
return( ret );
}
/* Check tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
{
mbedtls_zeroize( output, length );
return( MBEDTLS_ERR_CCM_AUTH_FAILED );
}
return( 0 );
}
#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C)
/*
* Examples 1 to 3 from SP800-38C Appendix C
*/
#define NB_TESTS 3
/*
* The data is the same for all tests, only the used length changes
*/
static const unsigned char key[] = {
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
};
static const unsigned char iv[] = {
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b
};
static const unsigned char ad[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13
};
static const unsigned char msg[] = {
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
};
static const size_t iv_len [NB_TESTS] = { 7, 8, 12 };
static const size_t add_len[NB_TESTS] = { 8, 16, 20 };
static const size_t msg_len[NB_TESTS] = { 4, 16, 24 };
static const size_t tag_len[NB_TESTS] = { 4, 6, 8 };
static const unsigned char res[NB_TESTS][32] = {
{ 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d },
{ 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62,
0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d,
0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd },
{ 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a,
0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b,
0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5,
0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 }
};
int mbedtls_ccm_self_test( int verbose )
{
mbedtls_ccm_context ctx;
unsigned char out[32];
size_t i;
int ret;
mbedtls_ccm_init( &ctx );
if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( " CCM: setup failed" );
return( 1 );
}
for( i = 0; i < NB_TESTS; i++ )
{
if( verbose != 0 )
mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 );
ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i],
iv, iv_len[i], ad, add_len[i],
msg, out,
out + msg_len[i], tag_len[i] );
if( ret != 0 ||
memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i],
iv, iv_len[i], ad, add_len[i],
res[i], out,
res[i] + msg_len[i], tag_len[i] );
if( ret != 0 ||
memcmp( out, msg, msg_len[i] ) != 0 )
{
if( verbose != 0 )
mbedtls_printf( "failed\n" );
return( 1 );
}
if( verbose != 0 )
mbedtls_printf( "passed\n" );
}
mbedtls_ccm_free( &ctx );
if( verbose != 0 )
mbedtls_printf( "\n" );
return( 0 );
}
#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */
#endif /* MBEDTLS_CCM_C */

917
lib/mbedtls/src/cipher.c Normal file
View File

@ -0,0 +1,917 @@
/**
* \file cipher.c
*
* \brief Generic cipher wrapper for mbed TLS
*
* \author Adriaan de Jong <dejong@fox-it.com>
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if defined(MBEDTLS_CIPHER_C)
#include "mbedtls/cipher.h"
#include "mbedtls/cipher_internal.h"
#include <stdlib.h>
#include <string.h>
#if defined(MBEDTLS_GCM_C)
#include "mbedtls/gcm.h"
#endif
#if defined(MBEDTLS_CCM_C)
#include "mbedtls/ccm.h"
#endif
#if defined(MBEDTLS_CMAC_C)
#include "mbedtls/cmac.h"
#endif
#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif
#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER)
#define MBEDTLS_CIPHER_MODE_STREAM
#endif
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize( void *v, size_t n ) {
volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0;
}
static int supported_init = 0;
const int *mbedtls_cipher_list( void )
{
const mbedtls_cipher_definition_t *def;
int *type;
if( ! supported_init )
{
def = mbedtls_cipher_definitions;
type = mbedtls_cipher_supported;
while( def->type != 0 )
*type++ = (*def++).type;
*type = 0;
supported_init = 1;
}
return( mbedtls_cipher_supported );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type )
{
const mbedtls_cipher_definition_t *def;
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( def->type == cipher_type )
return( def->info );
return( NULL );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name )
{
const mbedtls_cipher_definition_t *def;
if( NULL == cipher_name )
return( NULL );
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( ! strcmp( def->info->name, cipher_name ) )
return( def->info );
return( NULL );
}
const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id,
int key_bitlen,
const mbedtls_cipher_mode_t mode )
{
const mbedtls_cipher_definition_t *def;
for( def = mbedtls_cipher_definitions; def->info != NULL; def++ )
if( def->info->base->cipher == cipher_id &&
def->info->key_bitlen == (unsigned) key_bitlen &&
def->info->mode == mode )
return( def->info );
return( NULL );
}
void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx )
{
memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
}
void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx )
{
if( ctx == NULL )
return;
#if defined(MBEDTLS_CMAC_C)
if( ctx->cmac_ctx )
{
mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) );
mbedtls_free( ctx->cmac_ctx );
}
#endif
if( ctx->cipher_ctx )
ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx );
mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) );
}
int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info )
{
if( NULL == cipher_info || NULL == ctx )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) );
if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) )
return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED );
ctx->cipher_info = cipher_info;
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
/*
* Ignore possible errors caused by a cipher mode that doesn't use padding
*/
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
(void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 );
#else
(void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE );
#endif
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
return( 0 );
}
int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key,
int key_bitlen, const mbedtls_operation_t operation )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 &&
(int) ctx->cipher_info->key_bitlen != key_bitlen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
ctx->key_bitlen = key_bitlen;
ctx->operation = operation;
/*
* For CFB and CTR mode always use the encryption key schedule
*/
if( MBEDTLS_ENCRYPT == operation ||
MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
MBEDTLS_MODE_CTR == ctx->cipher_info->mode )
{
return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key,
ctx->key_bitlen );
}
if( MBEDTLS_DECRYPT == operation )
return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key,
ctx->key_bitlen );
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len )
{
size_t actual_iv_size;
if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
/* avoid buffer overflow in ctx->iv */
if( iv_len > MBEDTLS_MAX_IV_LENGTH )
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 )
actual_iv_size = iv_len;
else
{
actual_iv_size = ctx->cipher_info->iv_size;
/* avoid reading past the end of input buffer */
if( actual_iv_size > iv_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
memcpy( ctx->iv, iv, actual_iv_size );
ctx->iv_size = actual_iv_size;
return( 0 );
}
int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
ctx->unprocessed_len = 0;
return( 0 );
}
#if defined(MBEDTLS_GCM_C)
int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx,
const unsigned char *ad, size_t ad_len )
{
if( NULL == ctx || NULL == ctx->cipher_info )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation,
ctx->iv, ctx->iv_size, ad, ad_len );
}
return( 0 );
}
#endif /* MBEDTLS_GCM_C */
int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input,
size_t ilen, unsigned char *output, size_t *olen )
{
int ret;
size_t block_size = 0;
if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
*olen = 0;
block_size = mbedtls_cipher_get_block_size( ctx );
if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB )
{
if( ilen != block_size )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
*olen = ilen;
if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx,
ctx->operation, input, output ) ) )
{
return( ret );
}
return( 0 );
}
#if defined(MBEDTLS_GCM_C)
if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM )
{
*olen = ilen;
return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input,
output );
}
#endif
if ( 0 == block_size )
{
return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
}
if( input == output &&
( ctx->unprocessed_len != 0 || ilen % block_size ) )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC )
{
size_t copy_len = 0;
/*
* If there is not enough data for a full block, cache it.
*/
if( ( ctx->operation == MBEDTLS_DECRYPT &&
ilen + ctx->unprocessed_len <= block_size ) ||
( ctx->operation == MBEDTLS_ENCRYPT &&
ilen + ctx->unprocessed_len < block_size ) )
{
memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
ilen );
ctx->unprocessed_len += ilen;
return( 0 );
}
/*
* Process cached data first
*/
if( 0 != ctx->unprocessed_len )
{
copy_len = block_size - ctx->unprocessed_len;
memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input,
copy_len );
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, block_size, ctx->iv,
ctx->unprocessed_data, output ) ) )
{
return( ret );
}
*olen += block_size;
output += block_size;
ctx->unprocessed_len = 0;
input += copy_len;
ilen -= copy_len;
}
/*
* Cache final, incomplete block
*/
if( 0 != ilen )
{
if( 0 == block_size )
{
return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT;
}
copy_len = ilen % block_size;
if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT )
copy_len = block_size;
memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ),
copy_len );
ctx->unprocessed_len += copy_len;
ilen -= copy_len;
}
/*
* Process remaining full blocks
*/
if( ilen )
{
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, ilen, ctx->iv, input, output ) ) )
{
return( ret );
}
*olen += ilen;
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CBC */
#if defined(MBEDTLS_CIPHER_MODE_CFB)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB )
{
if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx,
ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv,
input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CFB */
#if defined(MBEDTLS_CIPHER_MODE_CTR)
if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR )
{
if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx,
ilen, &ctx->unprocessed_len, ctx->iv,
ctx->unprocessed_data, input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_CTR */
#if defined(MBEDTLS_CIPHER_MODE_STREAM)
if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM )
{
if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx,
ilen, input, output ) ) )
{
return( ret );
}
*olen = ilen;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_STREAM */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
/*
* PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len
*/
static void add_pkcs_padding( unsigned char *output, size_t output_len,
size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i;
for( i = 0; i < padding_len; i++ )
output[data_len + i] = (unsigned char) padding_len;
}
static int get_pkcs_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i, pad_idx;
unsigned char padding_len, bad = 0;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
padding_len = input[input_len - 1];
*data_len = input_len - padding_len;
/* Avoid logical || since it results in a branch */
bad |= padding_len > input_len;
bad |= padding_len == 0;
/* The number of bytes checked must be independent of padding_len,
* so pick input_len, which is usually 8 or 16 (one block) */
pad_idx = input_len - padding_len;
for( i = 0; i < input_len; i++ )
bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx );
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */
#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
/*
* One and zeros padding: fill with 80 00 ... 00
*/
static void add_one_and_zeros_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i = 0;
output[data_len] = 0x80;
for( i = 1; i < padding_len; i++ )
output[data_len + i] = 0x00;
}
static int get_one_and_zeros_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i;
unsigned char done = 0, prev_done, bad;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
bad = 0xFF;
*data_len = 0;
for( i = input_len; i > 0; i-- )
{
prev_done = done;
done |= ( input[i-1] != 0 );
*data_len |= ( i - 1 ) * ( done != prev_done );
bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done );
}
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
/*
* Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length
*/
static void add_zeros_and_len_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t padding_len = output_len - data_len;
unsigned char i = 0;
for( i = 1; i < padding_len; i++ )
output[data_len + i - 1] = 0x00;
output[output_len - 1] = (unsigned char) padding_len;
}
static int get_zeros_and_len_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i, pad_idx;
unsigned char padding_len, bad = 0;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
padding_len = input[input_len - 1];
*data_len = input_len - padding_len;
/* Avoid logical || since it results in a branch */
bad |= padding_len > input_len;
bad |= padding_len == 0;
/* The number of bytes checked must be independent of padding_len */
pad_idx = input_len - padding_len;
for( i = 0; i < input_len - 1; i++ )
bad |= input[i] * ( i >= pad_idx );
return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) );
}
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
/*
* Zero padding: fill with 00 ... 00
*/
static void add_zeros_padding( unsigned char *output,
size_t output_len, size_t data_len )
{
size_t i;
for( i = data_len; i < output_len; i++ )
output[i] = 0x00;
}
static int get_zeros_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
size_t i;
unsigned char done = 0, prev_done;
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*data_len = 0;
for( i = input_len; i > 0; i-- )
{
prev_done = done;
done |= ( input[i-1] != 0 );
*data_len |= i * ( done != prev_done );
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */
/*
* No padding: don't pad :)
*
* There is no add_padding function (check for NULL in mbedtls_cipher_finish)
* but a trivial get_padding function
*/
static int get_no_padding( unsigned char *input, size_t input_len,
size_t *data_len )
{
if( NULL == input || NULL == data_len )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*data_len = input_len;
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx,
unsigned char *output, size_t *olen )
{
if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
*olen = 0;
if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode ||
MBEDTLS_MODE_CTR == ctx->cipher_info->mode ||
MBEDTLS_MODE_GCM == ctx->cipher_info->mode ||
MBEDTLS_MODE_STREAM == ctx->cipher_info->mode )
{
return( 0 );
}
if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode )
{
if( ctx->unprocessed_len != 0 )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_CBC)
if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode )
{
int ret = 0;
if( MBEDTLS_ENCRYPT == ctx->operation )
{
/* check for 'no padding' mode */
if( NULL == ctx->add_padding )
{
if( 0 != ctx->unprocessed_len )
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
return( 0 );
}
ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ),
ctx->unprocessed_len );
}
else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len )
{
/*
* For decrypt operations, expect a full block,
* or an empty block if no padding
*/
if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len )
return( 0 );
return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED );
}
/* cipher block */
if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx,
ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv,
ctx->unprocessed_data, output ) ) )
{
return( ret );
}
/* Set output size for decryption */
if( MBEDTLS_DECRYPT == ctx->operation )
return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ),
olen );
/* Set output size for encryption */
*olen = mbedtls_cipher_get_block_size( ctx );
return( 0 );
}
#else
((void) output);
#endif /* MBEDTLS_CIPHER_MODE_CBC */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING)
int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode )
{
if( NULL == ctx ||
MBEDTLS_MODE_CBC != ctx->cipher_info->mode )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
switch( mode )
{
#if defined(MBEDTLS_CIPHER_PADDING_PKCS7)
case MBEDTLS_PADDING_PKCS7:
ctx->add_padding = add_pkcs_padding;
ctx->get_padding = get_pkcs_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS)
case MBEDTLS_PADDING_ONE_AND_ZEROS:
ctx->add_padding = add_one_and_zeros_padding;
ctx->get_padding = get_one_and_zeros_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN)
case MBEDTLS_PADDING_ZEROS_AND_LEN:
ctx->add_padding = add_zeros_and_len_padding;
ctx->get_padding = get_zeros_and_len_padding;
break;
#endif
#if defined(MBEDTLS_CIPHER_PADDING_ZEROS)
case MBEDTLS_PADDING_ZEROS:
ctx->add_padding = add_zeros_padding;
ctx->get_padding = get_zeros_padding;
break;
#endif
case MBEDTLS_PADDING_NONE:
ctx->add_padding = NULL;
ctx->get_padding = get_no_padding;
break;
default:
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
return( 0 );
}
#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */
#if defined(MBEDTLS_GCM_C)
int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx,
unsigned char *tag, size_t tag_len )
{
if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_ENCRYPT != ctx->operation )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len );
return( 0 );
}
int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx,
const unsigned char *tag, size_t tag_len )
{
int ret;
if( NULL == ctx || NULL == ctx->cipher_info ||
MBEDTLS_DECRYPT != ctx->operation )
{
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
}
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
unsigned char check_tag[16];
size_t i;
int diff;
if( tag_len > sizeof( check_tag ) )
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx,
check_tag, tag_len ) ) )
{
return( ret );
}
/* Check the tag in "constant-time" */
for( diff = 0, i = 0; i < tag_len; i++ )
diff |= tag[i] ^ check_tag[i];
if( diff != 0 )
return( MBEDTLS_ERR_CIPHER_AUTH_FAILED );
return( 0 );
}
return( 0 );
}
#endif /* MBEDTLS_GCM_C */
/*
* Packet-oriented wrapper for non-AEAD modes
*/
int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen )
{
int ret;
size_t finish_olen;
if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 )
return( ret );
if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 )
return( ret );
*olen += finish_olen;
return( 0 );
}
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
/*
* Packet-oriented encryption for AEAD modes
*/
int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
unsigned char *tag, size_t tag_len )
{
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
*olen = ilen;
return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen,
iv, iv_len, ad, ad_len, input, output,
tag_len, tag ) );
}
#endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_CCM_C)
if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
{
*olen = ilen;
return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len, input, output,
tag, tag_len ) );
}
#endif /* MBEDTLS_CCM_C */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
/*
* Packet-oriented decryption for AEAD modes
*/
int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
const unsigned char *iv, size_t iv_len,
const unsigned char *ad, size_t ad_len,
const unsigned char *input, size_t ilen,
unsigned char *output, size_t *olen,
const unsigned char *tag, size_t tag_len )
{
#if defined(MBEDTLS_GCM_C)
if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode )
{
int ret;
*olen = ilen;
ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len,
tag, tag_len, input, output );
if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED )
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
return( ret );
}
#endif /* MBEDTLS_GCM_C */
#if defined(MBEDTLS_CCM_C)
if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode )
{
int ret;
*olen = ilen;
ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen,
iv, iv_len, ad, ad_len,
input, output, tag, tag_len );
if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED )
ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED;
return( ret );
}
#endif /* MBEDTLS_CCM_C */
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
}
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
#endif /* MBEDTLS_CIPHER_C */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
# Ethernet Arduino Library for ESP32
See https://github.com/espressif/arduino-esp32/issues/3554#issuecomment-596902806

View File

@ -0,0 +1,82 @@
#include <ETH.h>
#define ETH_ADDR 1
#define ETH_POWER_PIN 5
#define ETH_MDC_PIN 23
#define ETH_MDIO_PIN 18
#define ETH_TYPE ETH_PHY_IP101
static bool eth_connected = false;
void WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
//set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}
void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}
Serial.println("closing connection\n");
client.stop();
}
void setup()
{
Serial.begin(115200);
WiFi.onEvent(WiFiEvent);
ETH.begin(ETH_ADDR, ETH_POWER_PIN, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_TYPE);
}
void loop()
{
if (eth_connected) {
testClient("google.com", 80);
}
delay(10000);
}

View File

@ -0,0 +1,17 @@
name=ESP32 Ethernet
version=1.1.0
author=Espressif
maintainer=Espressif
sentence=Ethernet Library for ESP32
paragraph=This library allows ESP32 to use ethernet hardware
category=Communication
url=
architectures=esp32

View File

@ -0,0 +1,299 @@
/*
ETH.h - espre ETH PHY support.
Based on WiFi.h from Arduino WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
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,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "ETH.h"
#include "eth_phy/phy.h"
#include "eth_phy/phy_tlk110.h"
#include "eth_phy/phy_lan8720.h"
#include "eth_phy/phy_ip101.h"
#include "lwip/err.h"
#include "lwip/dns.h"
extern void tcpipInit();
static int _eth_phy_mdc_pin = -1;
static int _eth_phy_mdio_pin = -1;
static int _eth_phy_power_pin = -1;
static eth_phy_power_enable_func _eth_phy_power_enable_orig = NULL;
static void _eth_phy_config_gpio(void)
{
if(_eth_phy_mdc_pin < 0 || _eth_phy_mdio_pin < 0){
log_e("MDC and MDIO pins are not configured!");
return;
}
phy_rmii_configure_data_interface_pins();
phy_rmii_smi_configure_pins(_eth_phy_mdc_pin, _eth_phy_mdio_pin);
}
static void _eth_phy_power_enable(bool enable)
{
pinMode(_eth_phy_power_pin, OUTPUT);
digitalWrite(_eth_phy_power_pin, enable);
delay(1);
}
ETHClass::ETHClass():initialized(false),started(false),staticIP(false)
{
}
ETHClass::~ETHClass()
{}
bool ETHClass::begin(uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t type, eth_clock_mode_t clock_mode)
{
esp_err_t err;
if(initialized){
err = esp_eth_enable();
if(err){
log_e("esp_eth_enable error: %d", err);
return false;
}
started = true;
return true;
}
_eth_phy_mdc_pin = mdc;
_eth_phy_mdio_pin = mdio;
_eth_phy_power_pin = power;
if(type == ETH_PHY_LAN8720)
{
eth_config_t config = phy_lan8720_default_ethernet_config;
memcpy(&eth_config, &config, sizeof(eth_config_t));
}
else if(type == ETH_PHY_TLK110)
{
eth_config_t config = phy_tlk110_default_ethernet_config;
memcpy(&eth_config, &config, sizeof(eth_config_t));
}
else if(type == ETH_PHY_IP101)
{
eth_config_t config = phy_ip101_default_ethernet_config;
memcpy(&eth_config, &config, sizeof(eth_config_t));
}
else
{
log_e("Bad ETH_PHY type: %u", (uint8_t)type);
return false;
}
eth_config.phy_addr = (eth_phy_base_t)phy_addr;
eth_config.clock_mode = clock_mode;
eth_config.gpio_config = _eth_phy_config_gpio;
eth_config.tcpip_input = tcpip_adapter_eth_input;
if(_eth_phy_power_pin >= 0){
_eth_phy_power_enable_orig = eth_config.phy_power_enable;
eth_config.phy_power_enable = _eth_phy_power_enable;
}
tcpipInit();
err = esp_eth_init(&eth_config);
if(!err){
initialized = true;
err = esp_eth_enable();
if(err){
log_e("esp_eth_enable error: %d", err);
} else {
started = true;
return true;
}
} else {
log_e("esp_eth_init error: %d", err);
}
return false;
}
bool ETHClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1, IPAddress dns2)
{
esp_err_t err = ESP_OK;
tcpip_adapter_ip_info_t info;
if(local_ip != (uint32_t)0x00000000){
info.ip.addr = static_cast<uint32_t>(local_ip);
info.gw.addr = static_cast<uint32_t>(gateway);
info.netmask.addr = static_cast<uint32_t>(subnet);
} else {
info.ip.addr = 0;
info.gw.addr = 0;
info.netmask.addr = 0;
}
err = tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_ETH);
if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STOPPED){
log_e("DHCP could not be stopped! Error: %d", err);
return false;
}
err = tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_ETH, &info);
if(err != ERR_OK){
log_e("STA IP could not be configured! Error: %d", err);
return false;
}
if(info.ip.addr){
staticIP = true;
} else {
err = tcpip_adapter_dhcpc_start(TCPIP_ADAPTER_IF_ETH);
if(err != ESP_OK && err != ESP_ERR_TCPIP_ADAPTER_DHCP_ALREADY_STARTED){
log_w("DHCP could not be started! Error: %d", err);
return false;
}
staticIP = false;
}
ip_addr_t d;
d.type = IPADDR_TYPE_V4;
if(dns1 != (uint32_t)0x00000000) {
// Set DNS1-Server
d.u_addr.ip4.addr = static_cast<uint32_t>(dns1);
dns_setserver(0, &d);
}
if(dns2 != (uint32_t)0x00000000) {
// Set DNS2-Server
d.u_addr.ip4.addr = static_cast<uint32_t>(dns2);
dns_setserver(1, &d);
}
return true;
}
IPAddress ETHClass::localIP()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return IPAddress();
}
return IPAddress(ip.ip.addr);
}
IPAddress ETHClass::subnetMask()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return IPAddress();
}
return IPAddress(ip.netmask.addr);
}
IPAddress ETHClass::gatewayIP()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return IPAddress();
}
return IPAddress(ip.gw.addr);
}
IPAddress ETHClass::dnsIP(uint8_t dns_no)
{
ip_addr_t dns_ip = dns_getserver(dns_no);
return IPAddress(dns_ip.u_addr.ip4.addr);
}
IPAddress ETHClass::broadcastIP()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return IPAddress();
}
return WiFiGenericClass::calculateBroadcast(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
}
IPAddress ETHClass::networkID()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return IPAddress();
}
return WiFiGenericClass::calculateNetworkID(IPAddress(ip.gw.addr), IPAddress(ip.netmask.addr));
}
uint8_t ETHClass::subnetCIDR()
{
tcpip_adapter_ip_info_t ip;
if(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)){
return (uint8_t)0;
}
return WiFiGenericClass::calculateSubnetCIDR(IPAddress(ip.netmask.addr));
}
const char * ETHClass::getHostname()
{
const char * hostname;
if(tcpip_adapter_get_hostname(TCPIP_ADAPTER_IF_ETH, &hostname)){
return NULL;
}
return hostname;
}
bool ETHClass::setHostname(const char * hostname)
{
return tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_ETH, hostname) == 0;
}
bool ETHClass::fullDuplex()
{
return eth_config.phy_get_duplex_mode();
}
bool ETHClass::linkUp()
{
return eth_config.phy_check_link();
}
uint8_t ETHClass::linkSpeed()
{
return eth_config.phy_get_speed_mode()?100:10;
}
bool ETHClass::enableIpV6()
{
return tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_ETH) == 0;
}
IPv6Address ETHClass::localIPv6()
{
static ip6_addr_t addr;
if(tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_ETH, &addr)){
return IPv6Address();
}
return IPv6Address(addr.addr);
}
uint8_t * macAddress(uint8_t* mac)
{
if(!mac){
return NULL;
}
esp_eth_get_mac(mac);
return mac;
}
String ETHClass::macAddress(void)
{
uint8_t mac[6];
char macStr[18] = { 0 };
esp_eth_get_mac(mac);
sprintf(macStr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
return String(macStr);
}
ETHClass ETH;

View File

@ -0,0 +1,95 @@
/*
ETH.h - espre ETH PHY support.
Based on WiFi.h from Ardiono WiFi shield library.
Copyright (c) 2011-2014 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
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,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _ETH_H_
#define _ETH_H_
#include "WiFi.h"
#include "esp_eth.h"
#ifndef ETH_PHY_ADDR
#define ETH_PHY_ADDR 0
#endif
#ifndef ETH_PHY_TYPE
#define ETH_PHY_TYPE ETH_PHY_LAN8720
#endif
#ifndef ETH_PHY_POWER
#define ETH_PHY_POWER -1
#endif
#ifndef ETH_PHY_MDC
#define ETH_PHY_MDC 23
#endif
#ifndef ETH_PHY_MDIO
#define ETH_PHY_MDIO 18
#endif
#ifndef ETH_CLK_MODE
#define ETH_CLK_MODE ETH_CLOCK_GPIO0_IN
#endif
typedef enum { ETH_PHY_LAN8720, ETH_PHY_TLK110, ETH_PHY_IP101, ETH_PHY_MAX } eth_phy_type_t;
class ETHClass {
private:
bool initialized;
bool started;
bool staticIP;
eth_config_t eth_config;
public:
ETHClass();
~ETHClass();
bool begin(uint8_t phy_addr=ETH_PHY_ADDR, int power=ETH_PHY_POWER, int mdc=ETH_PHY_MDC, int mdio=ETH_PHY_MDIO, eth_phy_type_t type=ETH_PHY_TYPE, eth_clock_mode_t clk_mode=ETH_CLK_MODE);
bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0x00000000, IPAddress dns2 = (uint32_t)0x00000000);
const char * getHostname();
bool setHostname(const char * hostname);
bool fullDuplex();
bool linkUp();
uint8_t linkSpeed();
bool enableIpV6();
IPv6Address localIPv6();
IPAddress localIP();
IPAddress subnetMask();
IPAddress gatewayIP();
IPAddress dnsIP(uint8_t dns_no = 0);
IPAddress broadcastIP();
IPAddress networkID();
uint8_t subnetCIDR();
uint8_t * macAddress(uint8_t* mac);
String macAddress();
friend class WiFiClient;
friend class WiFiServer;
};
extern ETHClass ETH;
#endif /* _ETH_H_ */

View File

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

View File

@ -1,5 +1,31 @@
## Unreleased (development)
### 8.3.1.6 20200617
- Add command ``Module2`` to configure fallback module on fast reboot (#8464)
- Add support for 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
- Add library to be used for decoding Teleinfo (French Metering Smart Meter)
- Add support for single wire LMT01 temperature Sensor by justifiably (#8713)
- Change ESP32 USER GPIO template representation decreasing template message size
- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT
- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset``
### 8.3.1.5 20200616
- Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3``
- Add Zigbee initial support for EmberZNet protocol (raw send/receive only)
### 8.3.1.4 20200615
- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON
### 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
- Add serial to TCP bridge, ``TCPStart`` and ``TCPBaudRate`` (needs #define USE_TCP_BRIDGE)
### 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]``

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;
//#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
#else
#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
#define make_stack_thunk_light(fcnToThunk) \
__asm("\n\
__asm__("\n\
.text\n\
.literal_position\n\
.literal .LC_STACK_VALUE"#fcnToThunk", 0xdeadbeef\n\

35
tasmota/WiFiClientSecureLightBearSSL.cpp Normal file → Executable file
View File

@ -21,10 +21,10 @@
*/
#include "my_user_config.h"
//#ifdef USE_MQTT_TLS
#if defined ESP8266 && (defined(USE_MQTT_TLS) || defined (USE_SENDMAIL))
#if defined(ESP8266) && defined(USE_TLS)
//#define DEBUG_TLS
// #define DEBUG_TLS
// #define DEBUG_ESP_SSL
#define LWIP_INTERNAL
@ -163,8 +163,8 @@ unsigned char *min_br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, si
//#define DEBUG_ESP_SSL
#ifdef DEBUG_ESP_SSL
#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
//#define DEBUG_BSSL(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__)
//#define DEBUG_BSSL(fmt, ...) DEBUG_ESP_PORT.printf_P((PGM_P)PSTR( "BSSL:" fmt), ## __VA_ARGS__)
#define DEBUG_BSSL(fmt, ...) Serial.printf(fmt, ## __VA_ARGS__)
#else
#define DEBUG_BSSL(...)
#endif
@ -276,6 +276,7 @@ bool WiFiClientSecure_light::flush(unsigned int maxWaitMs) {
}
int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
DEBUG_BSSL("connect(%s,%d)", ip.toString().c_str(), port);
clearLastError();
if (!WiFiClient::connect(ip, port)) {
setLastError(ERR_TCP_CONNECT);
@ -285,6 +286,7 @@ int WiFiClientSecure_light::connect(IPAddress ip, uint16_t port) {
}
int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
DEBUG_BSSL("connect(%s,%d)\n", name, port);
IPAddress remote_addr;
clearLastError();
if (!WiFi.hostByName(name, remote_addr)) {
@ -292,6 +294,7 @@ int WiFiClientSecure_light::connect(const char* name, uint16_t port) {
setLastError(ERR_CANT_RESOLVE_IP);
return 0;
}
DEBUG_BSSL("connect(%s,%d)\n", remote_addr.toString().c_str(), port);
if (!WiFiClient::connect(remote_addr, port)) {
DEBUG_BSSL("connect: Unable to connect TCP socket\n");
_last_error = ERR_TCP_CONNECT;
@ -709,10 +712,10 @@ extern "C" {
br_sha1_out(&sha1_context, xc->pubkey_recv_fingerprint); // copy to fingerprint
if (!xc->fingerprint_all) {
if (0 == memcmp(xc->fingerprint1, xc->pubkey_recv_fingerprint, 20)) {
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint1, 20)) {
return 0;
}
if (0 == memcmp(xc->fingerprint2, xc->pubkey_recv_fingerprint, 20)) {
if (0 == memcmp_P(xc->pubkey_recv_fingerprint, xc->fingerprint2, 20)) {
return 0;
}
return 1; // no match, error
@ -759,7 +762,7 @@ extern "C" {
// We limit to a single cipher to reduce footprint
// we reference it, don't put in PROGMEM
static const uint16_t suites[] = {
#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER)
#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
#else
BR_TLS_RSA_WITH_AES_128_GCM_SHA256
@ -786,7 +789,7 @@ extern "C" {
br_ssl_engine_set_aes_ctr(&cc->eng, &br_aes_small_ctr_vtable);
br_ssl_engine_set_ghash(&cc->eng, &br_ghash_ctmul32);
#if defined(USE_MQTT_AWS_IOT) || defined(USE_MQTT_TLS_FORCE_EC_CIPHER)
#ifdef USE_MQTT_TLS_FORCE_EC_CIPHER
// we support only P256 EC curve for AWS IoT, no EC curve for Letsencrypt unless forced
br_ssl_engine_set_ec(&cc->eng, &br_ec_p256_m15);
#endif
@ -796,12 +799,12 @@ extern "C" {
// Called by connect() to do the actual SSL setup and handshake.
// Returns if the SSL handshake succeeded.
bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
#ifdef USE_MQTT_AWS_IOT
if ((!_chain_P) || (!_sk_ec_P)) {
setLastError(ERR_MISSING_EC_KEY);
return false;
}
#endif
// #ifdef USE_MQTT_AWS_IOT
// if ((!_chain_P) || (!_sk_ec_P)) {
// setLastError(ERR_MISSING_EC_KEY);
// return false;
// }
// #endif
// Validation context, either full CA validation or checking only fingerprints
#ifdef USE_MQTT_TLS_CA_CERT
@ -909,4 +912,4 @@ bool WiFiClientSecure_light::_connectSSL(const char* hostName) {
#include "t_bearssl_tasmota_config.h"
#endif // USE_MQTT_TLS
#endif // USE_TLS

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

@ -24,7 +24,7 @@
#ifndef wificlientlightbearssl_h
#define wificlientlightbearssl_h
#if defined(USE_MQTT_TLS) || defined (USE_SENDMAIL)
#ifdef USE_TLS
#include <vector>
#include "WiFiClient.h"
#include <t_bearssl.h>
@ -148,7 +148,7 @@ class WiFiClientSecure_light : public WiFiClient {
#define ERR_OOM -1000
#define ERR_CANT_RESOLVE_IP -1001
#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
// For reference, BearSSL error codes:
@ -217,5 +217,5 @@ class WiFiClientSecure_light : public WiFiClient {
};
#endif // USE_MQTT_TLS
#endif // USE_TLS
#endif // wificlientlightbearssl_h

View File

@ -271,6 +271,8 @@
#define D_CMND_SSID "SSId"
#define D_CMND_PASSWORD "Password"
#define D_CMND_HOSTNAME "Hostname"
#define D_CMND_WIFI "Wifi"
#define D_CMND_ETHERNET "Ethernet"
#define D_CMND_WIFICONFIG "WifiConfig"
#define D_WCFG_0_RESTART "Restart"
#define D_WCFG_2_WIFIMANAGER "WifiManager"
@ -503,10 +505,14 @@
#define D_CMND_ZIGBEE_RESET "Reset"
#define D_JSON_ZIGBEE_CC2530 "CC2530"
#define D_CMND_ZIGBEEZNPRECEIVE "ZNPReceive" // only for debug
#define D_CMND_ZIGBEE_EZSP_RECEIVE "EZSPReceive" // only for debug
#define D_CMND_ZIGBEEZNPSEND "ZNPSend"
#define D_CMND_ZIGBEE_EZSP_SEND "EZSPSend"
#define D_JSON_ZIGBEE_STATE "ZbState"
#define D_JSON_ZIGBEEZNPRECEIVED "ZbZNPReceived"
#define D_JSON_ZIGBEE_EZSP_RECEIVED "ZbEZSPReceived"
#define D_JSON_ZIGBEEZNPSENT "ZbZNPSent"
#define D_JSON_ZIGBEE_EZSP_SENT "ZbEZSPSent"
#define D_JSON_ZIGBEEZCL_RECEIVED "ZbZCLReceived"
#define D_JSON_ZIGBEEZCL_RAW_RECEIVED "ZbZCLRawReceived"
#define D_JSON_ZIGBEE_DEVICE "Device"
@ -641,6 +647,7 @@
#define D_LOG_UPNP "UPP: " // UPnP
#define D_LOG_WIFI "WIF: " // Wifi
#define D_LOG_ZIGBEE "ZIG: " // Zigbee
#define D_LOG_TCP "TCP: " // TCP bridge
/********************************************************************************************/

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Подобрена комуникация"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Използвана енергия днес"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotřeba Dnes"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Erweiterte Kommunikation"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energie heute"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Βελτίωση επικοινωνίας"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Ενέργεια σήμερα"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Mejora de Comunicación"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX ESCENA TX"
#define D_KNX_RX_SCENE "KNX ESCENA RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energía Hoy"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Amélioration de la communication"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX Scène TX"
#define D_KNX_RX_SCENE "KNX Scène RX"
// xsns_03_energy.ino
#define D_ENERGY_TODAY "Énergie aujourd'hui"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "Hibernation"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Esclave TX"
#define D_SENSOR_SLAVE_RX "Esclave RX"
#define D_SENSOR_SLAVE_RESET "Esclave Rst"
#define D_SENSOR_CLIENT_TX "Esclave TX"
#define D_SENSOR_CLIENT_RX "Esclave RX"
#define D_SENSOR_CLIENT_RESET "Esclave Rst"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "שיפור התקשורת"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "צריכה יומית"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Mai energia"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Miglioramento comunicazione"
#define D_KNX_TX_SLOT "KNX - TX"
#define D_KNX_RX_SLOT "KNX - RX"
#define D_KNX_TX_SCENE "Scena - TX"
#define D_KNX_RX_SCENE "Scena - RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia - oggi"
@ -663,16 +665,16 @@
#define D_SENSOR_SM2135_DAT "SM2135 - DATI"
#define D_SENSOR_DEEPSLEEP "Deep sleep"
#define D_SENSOR_EXS_ENABLE "EXS - Abilita"
#define D_SENSOR_SLAVE_TX "Slave - TX"
#define D_SENSOR_SLAVE_RX "Slave - RX"
#define D_SENSOR_SLAVE_RESET "Slave - RST"
#define D_SENSOR_CLIENT_TX "Client - TX"
#define D_SENSOR_CLIENT_RX "Client - RX"
#define D_SENSOR_CLIENT_RESET "Client - RST"
#define D_SENSOR_GPS_RX "GPS - RX"
#define D_SENSOR_GPS_TX "GPS - TX"
#define D_SENSOR_HM10_RX "HM10 - RX"
#define D_SENSOR_HM10_TX "HM10 - TX"
#define D_SENSOR_LE01MR_RX "LE-01MR - RX"
#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_GDO2 "CC1101 - GDO2"
#define D_SENSOR_HRXL_RX "HRXL - RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "Velocità vento"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP - TX"
#define D_SENSOR_TCP_RXD "TCP - RX"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "커뮤니케이션 강화"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "금일 전력 사용량"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Verbeter verbinding"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Verbruik vandaag"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Rozszerzenia"
#define D_KNX_TX_SLOT "Gniazdo TX"
#define D_KNX_RX_SLOT "Gniazdo RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia dzisiaj"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "Głęboko uśpiony"
#define D_SENSOR_EXS_ENABLE "Załącz EXS"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Melhoria da comunicação"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Melhoria de Comunicação"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Consumo energético de hoje"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Îmbunătățire Communicație"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energia de Azi"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Энергия Сегодня"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "А"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Spotreba dnes"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Kommuniceringsförbättring"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energi idag"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Energy Today"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "A"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Підвищення зв'язку"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "Енергія Сьогодні"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "А"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "通讯增强"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用电量"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "安"

View File

@ -445,6 +445,8 @@
#define D_KNX_ENHANCEMENT "Communication Enhancement"
#define D_KNX_TX_SLOT "KNX TX"
#define D_KNX_RX_SLOT "KNX RX"
#define D_KNX_TX_SCENE "KNX SCENE TX"
#define D_KNX_RX_SCENE "KNX SCENE RX"
// xdrv_03_energy.ino
#define D_ENERGY_TODAY "今日用電量"
@ -663,9 +665,9 @@
#define D_SENSOR_SM2135_DAT "SM2135 Dat"
#define D_SENSOR_DEEPSLEEP "DeepSleep"
#define D_SENSOR_EXS_ENABLE "EXS Enable"
#define D_SENSOR_SLAVE_TX "Slave TX"
#define D_SENSOR_SLAVE_RX "Slave RX"
#define D_SENSOR_SLAVE_RESET "Slave RST"
#define D_SENSOR_CLIENT_TX "Client TX"
#define D_SENSOR_CLIENT_RX "Client RX"
#define D_SENSOR_CLIENT_RESET "Client RST"
#define D_SENSOR_GPS_RX "GPS RX"
#define D_SENSOR_GPS_TX "GPS TX"
#define D_SENSOR_HM10_RX "HM10 RX"
@ -681,6 +683,7 @@
#define D_SENSOR_WINDMETER_SPEED "WindMeter Spd"
#define D_SENSOR_TELEINFO_RX "TInfo Rx"
#define D_SENSOR_TELEINFO_ENABLE "TInfo EN"
#define D_SENSOR_LMT01_PULSE "LMT01 Pulse"
#define D_GPIO_WEBCAM_PWDN "CAM_PWDN"
#define D_GPIO_WEBCAM_RESET "CAM_RESET"
#define D_GPIO_WEBCAM_XCLK "CAM_XCLK"
@ -693,6 +696,11 @@
#define D_GPIO_WEBCAM_PSCLK "CAM_PSCLK"
#define D_GPIO_WEBCAM_HSD "CAM_HSD"
#define D_GPIO_WEBCAM_PSRCS "CAM_PSRCS"
#define D_SENSOR_ETH_PHY_POWER "ETH POWER"
#define D_SENSOR_ETH_PHY_MDC "ETH MDC"
#define D_SENSOR_ETH_PHY_MDIO "ETH MDIO"
#define D_SENSOR_TCP_TXD "TCP Tx"
#define D_SENSOR_TCP_RXD "TCP Rx"
// Units
#define D_UNIT_AMPERE "安"

View File

@ -50,7 +50,12 @@
#define PROJECT "tasmota" // PROJECT is used as the default topic delimiter
// If not selected the default will be SONOFF_BASIC
//#define MODULE SONOFF_BASIC // [Module] Select default model from tasmota_template.h
//#define MODULE SONOFF_BASIC // [Module] Select default module from tasmota_template.h
#ifdef ESP8266
#define FALLBACK_MODULE SONOFF_BASIC // [Module2] Select default module on fast reboot where USER_MODULE is user template
#else // ESP32
#define FALLBACK_MODULE WEMOS // [Module2] Select default module on fast reboot where USER_MODULE is user template
#endif
#define SAVE_DATA 1 // [SaveData] Save changed parameters to Flash (0 = disable, 1 - 3600 seconds)
#define SAVE_STATE true // [SetOption0] Save changed power state to Flash (false = disable, true = enable)
@ -135,6 +140,8 @@
// -- MQTT - Home Assistant Discovery -------------
#define HOME_ASSISTANT_DISCOVERY_ENABLE false // [SetOption19] Home Assistant Discovery (false = Disable, true = Enable)
#define HASS_AS_LIGHT false // [SetOption30] Enforce HAss autodiscovery as light
//#define DEEPSLEEP_LWT_HA_DISCOVERY // Enable LWT topic and its payloads for read-only sensors (Status sensor not included) and binary_sensors on HAss Discovery (Commented out: all read-only sensors and binary_sensors
// won't be shown as OFFLINE on Home Assistant when the device is DeepSleeping - NOTE: This is only for read-only sensors and binary_sensors, relays will be shown as OFFLINE)
// -- MQTT - Options ------------------------------
#define MQTT_RESULT_COMMAND false // [SetOption4] Switch between MQTT RESULT or COMMAND
@ -367,6 +374,11 @@
// Full documentation here: https://github.com/arendst/Tasmota/wiki/AWS-IoT
// #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 -----------------------------
//#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)
@ -522,6 +534,7 @@
// #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_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_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
@ -571,6 +584,7 @@
#define STARTING_OFFSET 30 // Turn on NovaSDS XX-seconds before tele_period is reached
//#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor (+1k4)
#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code)
//#define USE_TCP_BRIDGE // Add support for Serial to TCP bridge (+1.3k code)
//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop
#define MP3_VOLUME 10 // Set the startup volume on init, the range can be 0..30(max)
//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code)
@ -583,14 +597,11 @@
//#define USE_GPS // Add support for GPS and NTP Server for becoming Stratus 1 Time Source (+3k1 code, +132 bytes RAM)
// #define USE_FLOG // Add support for GPS logging in OTA's Flash (Experimental) (+2k9 code, +8 bytes RAM)
//#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge (+9k3 code)
//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
#define USE_TASMOTA_SLAVE_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
#define USE_TASMOTA_SLAVE_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k6 code, 64 mem)
#define USE_TASMOTA_CLIENT_FLASH_SPEED 57600 // Usually 57600 for 3.3V variants and 115200 for 5V variants
#define USE_TASMOTA_CLIENT_SERIAL_SPEED 57600 // Depends on the sketch that is running on the Uno/Pro Mini
//#define USE_OPENTHERM // Add support for OpenTherm (+15k code)
#define USE_TELEINFO // Add support for Teleinfo via serial RX interface
//#define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps)
// -- Power monitoring sensors --------------------
#define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code)
@ -614,6 +625,8 @@
#define LE01MR_SPEED 9600 // LE-01MR modbus baudrate (default: 9600)
#define LE01MR_ADDR 1 // LE-01MR modbus address (default: 0x01)
#define USE_BL0940 // Add support for BL0940 Energy monitor as used in Blitzwolf SHP-10 (+1k6 code)
//#define USE_TELEINFO // Add support for Teleinfo via serial RX interface (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM)
// #define USE_TELEINFO_STANDARD // Use standard mode (9600 bps) else it's historical mode (1200 bps)
// -- Low level interface devices -----------------
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor (1k6 code)
@ -624,6 +637,7 @@
#define MAX31865_PTD_RES 100 // Nominal PTD resistance at 0°C (100Ω for a PT100, 1000Ω for a PT1000, YMMV!)
#define MAX31865_REF_RES 430 // Reference resistor (Usually 430Ω for a PT100, 4300Ω for a PT1000)
#define MAX31865_PTD_BIAS 0 // To calibrate your not-so-good PTD
//#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code)
// -- IR Remote features - all protocols from IRremoteESP8266 --------------------------
// IR Full Protocols mode is activated through platform.io only.
@ -648,6 +662,9 @@
// -- Zigbee interface ----------------------------
//#define USE_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP (+49k code, +3k mem)
#define USE_ZIGBEE_ZNP // Enable ZNP protocol, needed for CC2530 based devices
// #define USE_ZIGBEE_EZSP // [EXPERIMENTAL - DO NOT USE] Enable EZSP protocol, needed for EFR32 EmberZNet based devices, like Sonoff Zigbee bridge
// Note: USE_ZIGBEE_ZNP and USE_ZIGBEE_EZSP are mutually incompatible, you must select exactly one
#define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home
// if PANID == 0xFFFF, then the device will act as a Zigbee router, the parameters below are ignored
// if PANID == 0xFFFE, then the device will act as a Zigbee end-device (non-router), the parameters below are ignored
@ -657,6 +674,8 @@
#define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices
#define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms)
#define USE_ZIGBEE_MODELID "Tasmota Z2T" // reported "ModelId" (cluster 0000 / attribute 0005)
#define USE_ZIGBEE_MANUFACTURER "Tasmota" // reported "Manufacturer" (cluster 0000 / attribute 0004)
// -- Other sensors/drivers -----------------------
@ -716,6 +735,28 @@
// -- End of general directives -------------------
/*********************************************************************************************\
* ESP32 only features
\*********************************************************************************************/
#ifdef ESP32
//#define USE_ETHERNET // Add support for ethernet (Currently fixed for Olimex ESP32-PoE)
// Olimex ESP32-PoE
#define ETH_TYPE 0 // [EthType] 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110, 2 = ETH_PHY_IP101
#define ETH_ADDR 0 // [EthAddress] 0 = PHY0 .. 31 = PHY31
#define ETH_CLKMODE 3 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
// wESP32-PoE
// #define ETH_TYPE 0 // [EthType] 0 = ETH_PHY_LAN8720, 1 = ETH_PHY_TLK110, 2 = ETH_PHY_IP101
// #define ETH_ADDR 0 // [EthAddress] 0 = PHY0 .. 31 = PHY31
// #define ETH_CLKMODE 0 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT
//#define USE_SPI // Add support for hardware SPI
//#define USE_MI_ESP32 // Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
//#define USE_WEBCAM // Add support for webcam
#endif
/*********************************************************************************************\
* Debug features
\*********************************************************************************************/
@ -755,4 +796,16 @@
#error "Select either USE_RULES or USE_SCRIPT. They can't both be used at the same time"
#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_

View File

@ -114,8 +114,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t pwm_ct_mode : 1; // bit 10 (v8.2.0.4) - SetOption92 - Set PWM Mode from regular PWM to ColorTemp control (Xiaomi Philips ...)
uint32_t compress_rules_cpu : 1; // bit 11 (v8.2.0.6) - SetOption93 - Keep uncompressed rules in memory to avoid CPU load of uncompressing at each tick
uint32_t max6675 : 1; // bit 12 (v8.3.1.2) - SetOption94 - Implement simpler MAX6675 protocol instead of MAX31855
uint32_t spare13 : 1;
uint32_t spare14 : 1;
uint32_t network_wifi : 1; // bit 13 (v8.3.1.3) - CMND_WIFI
uint32_t network_ethernet : 1; // bit 14 (v8.3.1.3) = CMND_ETHERNET
uint32_t spare15 : 1;
uint32_t spare16 : 1;
uint32_t spare17 : 1;
@ -392,12 +392,13 @@ struct {
#else // ESP32
myio my_gp; // 3AC - 2 x 40 bytes (ESP32)
mytmplt user_template; // 3FC - 2 x 37 bytes (ESP32)
uint8_t eth_type; // 446
uint8_t eth_clk_mode; // 447
uint8_t free_esp32_446[6]; // 446
uint8_t free_esp32_448[4]; // 448
WebCamCfg webcam_config; // 44C
uint8_t free_esp32_450[1]; // 450
uint8_t eth_address; // 450
#endif // ESP8266 - ESP32
char serial_delimiter; // 451
@ -568,8 +569,10 @@ struct {
uint8_t windmeter_tele_pchange; // F3E
uint8_t ledpwm_on; // F3F
uint8_t ledpwm_off; // F40
uint8_t tcp_baudrate; // F41
uint8_t fallback_module; // F42
uint8_t free_f42[119]; // F41 - Decrement if adding new Setting variables just above and below
uint8_t free_f43[117]; // F43 - Decrement if adding new Setting variables just above and below
// Only 32 bit boundary variables below
uint16_t pulse_counter_debounce_low; // FB8
@ -647,13 +650,14 @@ struct XDRVMAILBOX {
} XdrvMailbox;
#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
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
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint16_t data; // Allow bit manipulation
struct {
uint16_t system_init : 1; // Changing layout here needs adjustments in xdrv_10_rules.ino too
uint16_t system_boot : 1;
uint16_t time_init : 1;
uint16_t time_set : 1;
@ -664,7 +668,6 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint16_t http_init : 1;
uint16_t shutter_moved : 1;
uint16_t shutter_moving : 1;
uint16_t spare10 : 1;
uint16_t spare11 : 1;
uint16_t spare12 : 1;
uint16_t spare13 : 1;
@ -676,10 +679,10 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
typedef union {
uint8_t data;
struct {
uint8_t wifi_down : 1;
uint8_t network_down : 1;
uint8_t mqtt_down : 1;
uint8_t spare02 : 1;
uint8_t spare03 : 1;
uint8_t wifi_down : 1;
uint8_t eth_down : 1;
uint8_t spare04 : 1;
uint8_t spare05 : 1;
uint8_t spare06 : 1;

View File

@ -768,6 +768,7 @@ void SettingsDefaultSet2(void)
// flag.interlock |= 0;
Settings.interlock[0] = 0xFF; // Legacy support using all relays in one interlock group
Settings.module = MODULE;
Settings.fallback_module = FALLBACK_MODULE;
ModuleDefault(WEMOS);
// for (uint32_t i = 0; i < ARRAY_SIZE(Settings.my_gp.io); i++) { Settings.my_gp.io[i] = GPIO_NONE; }
SettingsUpdateText(SET_FRIENDLYNAME1, PSTR(FRIENDLY_NAME));
@ -798,7 +799,16 @@ void SettingsDefaultSet2(void)
Settings.serial_delimiter = 0xff;
Settings.seriallog_level = SERIAL_LOG_LEVEL;
// Ethernet
flag4.network_ethernet |= 1;
#ifdef ESP32
Settings.eth_type = ETH_TYPE;
Settings.eth_clk_mode = ETH_CLKMODE;
Settings.eth_address = ETH_ADDR;
#endif
// Wifi
flag4.network_wifi |= 1;
flag3.use_wifi_scan |= WIFI_SCAN_AT_RESTART;
flag3.use_wifi_rescan |= WIFI_SCAN_REGULARLY;
Settings.wifi_output_power = 170;
@ -1439,6 +1449,20 @@ void SettingsDelta(void)
Settings.ledpwm_on = 255;
Settings.ledpwm_mask = 0;
}
if (Settings.version < 0x08030104) {
Settings.flag4.network_wifi = 1;
Settings.flag4.network_ethernet = 1;
}
#ifdef ESP32
if (Settings.version < 0x08030105) {
Settings.eth_type = ETH_TYPE;
Settings.eth_clk_mode = ETH_CLKMODE;
Settings.eth_address = ETH_ADDR;
}
#endif
if (Settings.version < 0x08030106) {
Settings.fallback_module = FALLBACK_MODULE;
}
Settings.version = VERSION;
SettingsSave(1);

View File

@ -156,7 +156,7 @@ float CharToFloat(const char *str)
signed char sign = 1;
if (*pt == '-') { sign = -1; }
if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign
if (*pt == '-' || *pt == '+') { pt++; } // Skip any sign
float left = 0;
if (*pt != '.') {
@ -167,6 +167,9 @@ float CharToFloat(const char *str)
float right = 0;
if (*pt == '.') {
pt++;
uint32_t max_decimals = 0;
while ((max_decimals < 8) && isdigit(pt[max_decimals])) { max_decimals++; }
pt[max_decimals] = '\0'; // Limit decimals to float max of 8
right = atoi(pt); // Decimal part
while (isdigit(*pt)) {
pt++;
@ -687,9 +690,9 @@ void ResetGlobalValues(void)
{
if ((uptime - global_update) > GLOBAL_VALUES_VALID) { // Reset after 5 minutes
global_update = 0;
global_temperature = 9999;
global_humidity = 0;
global_pressure = 0;
global_temperature = NAN;
global_humidity = 0.0f;
global_pressure = 0.0f;
}
}
@ -997,7 +1000,7 @@ char* ResponseGetTime(uint32_t format, char* time_str)
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":%u"), UtcTime());
break;
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;
default:
snprintf_P(time_str, TIMESZ, PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
@ -1356,7 +1359,15 @@ bool JsonTemplate(const char* dataBuf)
}
if (obj[D_JSON_GPIO].success()) {
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
#ifdef ESP8266
Settings.user_template.gp.io[i] = obj[D_JSON_GPIO][i] | 0;
#else // ESP32
uint16_t gpio = obj[D_JSON_GPIO][i] | 0;
if (gpio == (AGPIO(GPIO_NONE) +1)) {
gpio = AGPIO(GPIO_USER);
}
Settings.user_template.gp.io[i] = gpio;
#endif
}
}
if (obj[D_JSON_FLAG].success()) {
@ -1375,7 +1386,15 @@ void TemplateJson(void)
{
Response_P(PSTR("{\"" D_JSON_NAME "\":\"%s\",\"" D_JSON_GPIO "\":["), SettingsText(SET_TEMPLATE_NAME));
for (uint32_t i = 0; i < ARRAY_SIZE(Settings.user_template.gp.io); i++) {
#ifdef ESP8266
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", Settings.user_template.gp.io[i]);
#else // ESP32
uint16_t gpio = Settings.user_template.gp.io[i];
if (gpio == AGPIO(GPIO_USER)) {
gpio = AGPIO(GPIO_NONE) +1;
}
ResponseAppend_P(PSTR("%s%d"), (i>0)?",":"", gpio);
#endif
}
ResponseAppend_P(PSTR("],\"" D_JSON_FLAG "\":%d,\"" D_JSON_BASE "\":%d}"), Settings.user_template.flag, Settings.user_template_base +1);
}
@ -1601,8 +1620,8 @@ void I2cScan(char *devs, unsigned int devs_len)
// Return error codes defined in twi.h and core_esp8266_si2c.c
// I2C_OK 0
// I2C_SCL_HELD_LOW 1 = SCL held low by another device, no procedure available to recover
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond slave clock stretch time
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by slave/another_master after n bits
// I2C_SCL_HELD_LOW_AFTER_READ 2 = I2C bus error. SCL held low beyond client clock stretch time
// I2C_SDA_HELD_LOW 3 = I2C bus error. SDA line held low by client/another_master after n bits
// I2C_SDA_HELD_LOW_AFTER_INIT 4 = line busy. SDA again held low by another device. 2nd master?
uint8_t error = 0;
@ -1738,7 +1757,7 @@ void Syslog(void)
}
if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) {
char syslog_preamble[64]; // Hostname + Id
snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname);
snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), NetworkHostname());
memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble));
log_data[sizeof(log_data) -1] = '\0';
memcpy(log_data, syslog_preamble, strlen(syslog_preamble));
@ -1785,7 +1804,7 @@ void AddLog(uint32_t loglevel)
!global_state.mqtt_down &&
(loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); }
if (!global_state.wifi_down &&
if (!global_state.network_down &&
(loglevel <= syslog_level)) { Syslog(); }
prepped_loglevel = 0;

View File

@ -27,7 +27,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix
D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|"
D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|"
D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_LEDPWM_ON "|" D_CMND_LEDPWM_OFF "|" D_CMND_LEDPWM_MODE "|"
D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|"
D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" D_CMND_WIFI "|"
#ifdef USE_I2C
D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|"
#endif
@ -54,7 +54,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = {
&CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig,
&CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd,
&CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode,
&CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum,
&CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndWifi,
#ifdef USE_I2C
&CmndI2cScan, CmndI2cDriver,
#endif
@ -499,8 +499,8 @@ void CmndStatus(void)
Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\""
D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\""
D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"),
my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(),
IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(),
NetworkHostname(), NetworkAddress().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(),
IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), NetworkMacAddress().c_str(),
Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str());
MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5"));
}
@ -626,7 +626,7 @@ void CmndGlobalTemp(void)
if (!isnan(temperature) && Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit
temperature = (temperature - 32) / 1.8; // Celsius
}
if ((temperature >= -50.0) && (temperature <= 100.0)) {
if ((temperature >= -50.0f) && (temperature <= 100.0f)) {
ConvertTemp(temperature);
global_update = 1; // Keep global values just entered valid
}
@ -1018,6 +1018,9 @@ void CmndModule(void)
present = ValidTemplateModule(XdrvMailbox.payload);
}
if (present) {
if (XdrvMailbox.index == 2) {
Settings.fallback_module = XdrvMailbox.payload;
} else {
Settings.last_module = Settings.module;
Settings.module = XdrvMailbox.payload;
SetModuleType();
@ -1029,7 +1032,15 @@ void CmndModule(void)
restart_flag = 2;
}
}
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, ModuleNr(), ModuleName().c_str());
}
uint8_t module_real = Settings.module;
uint8_t module_number = ModuleNr();
if (XdrvMailbox.index == 2) {
module_real = Settings.fallback_module;
module_number = (USER_MODULE == Settings.fallback_module) ? 0 : Settings.fallback_module +1;
strcat(XdrvMailbox.command, "2");
}
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, module_number, AnyModuleName(module_real).c_str());
}
void CmndModules(void)
@ -1497,6 +1508,15 @@ void CmndWifiConfig(void)
Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig));
}
void CmndWifi(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.flag4.network_wifi = XdrvMailbox.payload;
restart_flag = 2;
}
ResponseCmndStateText(Settings.flag4.network_wifi);
}
void CmndDevicename(void)
{
if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) {

View File

@ -477,8 +477,8 @@ void GetFeatures(void)
#ifdef USE_EXS_DIMMER
feature5 |= 0x00008000; // xdrv_30_exs_dimmer.ino
#endif
#ifdef USE_TASMOTA_SLAVE
feature5 |= 0x00010000; // xdrv_31_arduino_slave.ino
#ifdef USE_TASMOTA_CLIENT
feature5 |= 0x00010000; // xdrv_31_tasmota_client.ino
#endif
#ifdef USE_HIH6
feature5 |= 0x00020000; // xsns_55_hih_series.ino
@ -575,14 +575,21 @@ void GetFeatures(void)
#ifdef USE_BL0940
feature6 |= 0x00004000; // xnrg_14_bl0940.ino
#endif
#ifdef USE_TELEINFO
feature6 |= 0x00008000; // xnrg_15_teleinfo.ino
#ifdef USE_TELEGRAM
feature6 |= 0x00008000; // xdrv_40_telegram.ino
#endif
#ifdef USE_HP303B
feature6 |= 0x00010000; // xsns_73_hp303b.ino
#endif
#ifdef USE_TCP_BRIDGE
feature6 |= 0x00020000; // xdrv_41_tcp_bridge.ino
#endif
#ifdef USE_TELEINFO
feature6 |= 0x00040000; // xnrg_15_teleinfo.ino
#endif
#ifdef USE_LMT01
feature6 |= 0x00080000; // xsns_74_lmt01.ino
#endif
// feature6 |= 0x00010000;
// feature6 |= 0x00020000;
// feature6 |= 0x00040000;
// feature6 |= 0x00080000;
// feature6 |= 0x00100000;
// feature6 |= 0x00200000;
@ -596,8 +603,10 @@ void GetFeatures(void)
// feature6 |= 0x10000000;
// feature6 |= 0x20000000;
// feature6 |= 0x40000000;
#ifdef USE_ETHERNET
feature6 |= 0x40000000; // xdrv_82_ethernet.ino
#endif
#ifdef USE_WEBCAM
feature6 |= 0x80000000;
feature6 |= 0x80000000; // xdrv_81_webcam.ino
#endif
}

128
tasmota/support_network.ino Normal file
View File

@ -0,0 +1,128 @@
/*
support_network.ino - Network 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/>.
*/
/*********************************************************************************************\
* MDNS
\*********************************************************************************************/
struct {
uint8_t begun = 0; // mDNS active
} Mdns;
#ifdef USE_DISCOVERY
void StartMdns(void) {
if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service
if (!Mdns.begun) {
// if (mdns_delayed_start) {
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
// mdns_delayed_start--;
// } else {
// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
Mdns.begun = (uint8_t)MDNS.begin(my_hostname);
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Mdns.begun) ? D_INITIALIZED : D_FAILED);
// }
}
}
}
#ifdef MQTT_HOST_DISCOVERY
void MqttDiscoverServer(void)
{
if (!Mdns.begun) { return; }
int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
if (n > 0) {
uint32_t i = 0; // If the hostname isn't set, use the first record found.
#ifdef MDNS_HOSTNAME
for (i = n; i > 0; i--) { // Search from last to first and use first if not found
if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) {
break; // Stop at matching record
}
}
#endif // MDNS_HOSTNAME
SettingsUpdateText(SET_MQTT_HOST, MDNS.IP(i).toString().c_str());
Settings.mqtt_port = MDNS.port(i);
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), SettingsText(SET_MQTT_HOST), Settings.mqtt_port);
}
}
#endif // MQTT_HOST_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
void MdnsAddServiceHttp(void) {
if (1 == Mdns.begun) {
Mdns.begun = 2;
MDNS.addService("http", "tcp", WEB_PORT);
}
}
void MdnsUpdate(void) {
if (2 == Mdns.begun) {
MDNS.update();
AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update");
}
}
#endif // WEBSERVER_ADVERTISE
#endif // USE_DISCOVERY
/*********************************************************************************************\
* Global network parameters
\*********************************************************************************************/
char* NetworkHostname(void) {
if (global_state.eth_down) {
return my_hostname;
}
#ifdef ESP32
#ifdef USE_ETHERNET
else {
return EthernetHostname();
}
#endif
#endif
}
IPAddress NetworkAddress(void) {
if (global_state.eth_down) {
return WiFi.localIP();
}
#ifdef ESP32
#ifdef USE_ETHERNET
else {
return EthernetLocalIP();
}
#endif
#endif
}
String NetworkMacAddress(void) {
if (global_state.eth_down) {
return WiFi.macAddress();
}
#ifdef ESP32
#ifdef USE_ETHERNET
else {
return EthernetMacAddress();
}
#endif
#endif
}

View File

@ -206,6 +206,14 @@ String GetDateAndTime(uint8_t time_type)
break;
}
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
dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00
}
@ -371,7 +379,7 @@ void RtcSecond(void)
Rtc.millis = millis();
if (!Rtc.user_time_entry) {
if (!global_state.wifi_down) {
if (!global_state.network_down) {
uint8_t uptime_minute = (uptime / 60) % 60; // 0 .. 59
if ((Rtc.ntp_sync_minute > 59) && (uptime_minute > 2)) {
Rtc.ntp_sync_minute = 1; // If sync prepare for a new cycle

View File

@ -684,10 +684,14 @@ void MqttShowState(void)
MqttShowPWMState();
}
if (!global_state.wifi_down) {
int32_t rssi = WiFi.RSSI();
ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"),
ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}"),
Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(),
WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str());
}
ResponseJsonEnd();
}
void MqttPublishTeleState(void)
@ -824,7 +828,7 @@ void PerformEverySecond(void)
if (Settings.tele_period) {
if (tele_period >= 9999) {
if (!global_state.wifi_down) {
if (!global_state.network_down) {
tele_period = 0; // Allow teleperiod once wifi is connected
}
} else {
@ -916,10 +920,12 @@ void Every250mSeconds(void)
state_250mS++;
state_250mS &= 0x3;
if (!Settings.flag.global_state) { // Problem blinkyblinky enabled - SetOption31 - Control link led blinking
if (global_state.data) { // Any problem
global_state.network_down = (global_state.wifi_down && global_state.eth_down);
if (!Settings.flag.global_state && !global_state.network_down) { // SetOption31 - Control link led blinking
if (global_state.data &0x03) { // Any problem
if (global_state.mqtt_down) { blinkinterval = 7; } // MQTT problem so blink every 2 seconds (slowest)
if (global_state.wifi_down) { blinkinterval = 3; } // Wifi problem so blink every second (slow)
if (global_state.network_down) { blinkinterval = 3; } // Network problem so blink every second (slow)
blinks = 201; // Allow only a single blink in case the problem is solved
}
}
@ -1151,11 +1157,75 @@ void Every250mSeconds(void)
}
break;
case 2: // Every x.5 second
if (Settings.flag4.network_wifi) {
WifiCheck(wifi_state_flag);
wifi_state_flag = WIFI_RESTART;
}
break;
case 3: // Every x.75 second
if (!global_state.wifi_down) { MqttCheck(); }
if (!global_state.network_down) {
#ifdef FIRMWARE_MINIMAL
if (1 == RtcSettings.ota_loader) {
RtcSettings.ota_loader = 0;
ota_state_flag = 3;
}
#endif // FIRMWARE_MINIMAL
#ifdef USE_DISCOVERY
StartMdns();
#endif // USE_DISCOVERY
#ifdef USE_WEBSERVER
if (Settings.webserver) {
#ifdef ESP8266
StartWebserver(Settings.webserver, WiFi.localIP());
#else // ESP32
#ifdef USE_ETHERNET
StartWebserver(Settings.webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP());
#else
StartWebserver(Settings.webserver, WiFi.localIP());
#endif
#endif
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
MdnsAddServiceHttp();
#endif // WEBSERVER_ADVERTISE
#endif // USE_DISCOVERY
} else {
StopWebserver();
}
#ifdef USE_EMULATION
if (Settings.flag2.emulation) { UdpConnect(); }
#endif // USE_EMULATION
#endif // USE_WEBSERVER
#ifdef USE_DEVICE_GROUPS
DeviceGroupsStart();
#endif // USE_DEVICE_GROUPS
#ifdef USE_KNX
if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED
KNXStart();
knx_started = true;
}
#endif // USE_KNX
MqttCheck();
} else {
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
#ifdef USE_DEVICE_GROUPS
DeviceGroupsStop();
#endif // USE_DEVICE_GROUPS
#ifdef USE_KNX
knx_started = false;
#endif // USE_KNX
}
break;
}
}
@ -1174,7 +1244,7 @@ uint16_t arduino_ota_progress_dot_count = 0;
void ArduinoOTAInit(void)
{
ArduinoOTA.setPort(8266);
ArduinoOTA.setHostname(my_hostname);
ArduinoOTA.setHostname(NetworkHostname());
if (strlen(SettingsText(SET_WEBPWD))) {
ArduinoOTA.setPassword(SettingsText(SET_WEBPWD));
}

View File

@ -52,7 +52,6 @@ struct WIFI {
uint8_t status;
uint8_t config_type = 0;
uint8_t config_counter = 0;
uint8_t mdns_begun = 0; // mDNS active
uint8_t scan_state;
uint8_t bssid[6];
int8_t best_network_db;
@ -352,6 +351,9 @@ void WifiSetState(uint8_t state)
}
}
global_state.wifi_down = state ^1;
if (!global_state.wifi_down) {
global_state.network_down = 0;
}
}
#if LWIP_IPV6
@ -410,10 +412,7 @@ void WifiCheckIp(void)
Wifi.status = WL_CONNECTED;
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
if (2 == Wifi.mdns_begun) {
MDNS.update();
AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update");
}
MdnsUpdate();
#endif // USE_DISCOVERY
#endif // WEBSERVER_ADVERTISE
} else {
@ -529,75 +528,14 @@ void WifiCheck(uint8_t param)
if ((WL_CONNECTED == WiFi.status()) && (static_cast<uint32_t>(WiFi.localIP()) != 0) && !Wifi.config_type) {
#endif // LWIP_IPV6=1
WifiSetState(1);
if (Settings.flag3.use_wifi_rescan) { // SetOption57 - Scan wifi network every 44 minutes for configured AP's
if (!(uptime % (60 * WIFI_RESCAN_MINUTES))) {
Wifi.scan_state = 2;
}
}
#ifdef FIRMWARE_MINIMAL
if (1 == RtcSettings.ota_loader) {
RtcSettings.ota_loader = 0;
ota_state_flag = 3;
}
#endif // FIRMWARE_MINIMAL
#ifdef USE_DISCOVERY
if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service
if (!Wifi.mdns_begun) {
// if (mdns_delayed_start) {
// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION));
// mdns_delayed_start--;
// } else {
// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START];
Wifi.mdns_begun = (uint8_t)MDNS.begin(my_hostname);
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Wifi.mdns_begun) ? D_INITIALIZED : D_FAILED);
// }
}
}
#endif // USE_DISCOVERY
#ifdef USE_WEBSERVER
if (Settings.webserver) {
StartWebserver(Settings.webserver, WiFi.localIP());
#ifdef USE_DISCOVERY
#ifdef WEBSERVER_ADVERTISE
if (1 == Wifi.mdns_begun) {
Wifi.mdns_begun = 2;
MDNS.addService("http", "tcp", WEB_PORT);
}
#endif // WEBSERVER_ADVERTISE
#endif // USE_DISCOVERY
} else {
StopWebserver();
}
#ifdef USE_EMULATION
if (Settings.flag2.emulation) { UdpConnect(); }
#endif // USE_EMULATION
#endif // USE_WEBSERVER
#ifdef USE_DEVICE_GROUPS
DeviceGroupsStart();
#endif // USE_DEVICE_GROUPS
#ifdef USE_KNX
if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED
KNXStart();
knx_started = true;
}
#endif // USE_KNX
} else {
WifiSetState(0);
#ifdef USE_EMULATION
UdpDisconnect();
#endif // USE_EMULATION
#ifdef USE_DEVICE_GROUPS
DeviceGroupsStop();
#endif // USE_DEVICE_GROUPS
Wifi.mdns_begun = 0;
#ifdef USE_KNX
knx_started = false;
#endif // USE_KNX
Mdns.begun = 0;
}
}
}
@ -652,6 +590,8 @@ RF_PRE_INIT()
void WifiConnect(void)
{
if (!Settings.flag4.network_wifi) { return; }
WifiSetState(0);
WifiSetOutputPower();
WiFi.persistent(false); // Solve possible wifi init errors

View File

@ -203,7 +203,8 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to
#define KNX_SLOT3 28
#define KNX_SLOT4 29
#define KNX_SLOT5 30
#define KNX_MAX_device_param 30
#define KNX_SCENE 31
#define KNX_MAX_device_param 31
#define MAX_KNXTX_CMNDS 5
/*********************************************************************************************\
@ -214,7 +215,7 @@ enum WeekInMonthOptions {Last, First, Second, Third, Fourth};
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 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};
@ -293,7 +294,7 @@ enum SettingsTextIndex { SET_OTAURL,
SET_TEMPLATE_NAME,
SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4,
SET_DEVICENAME,
SET_TELEGRAMTOKEN,
SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID,
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 };
@ -321,9 +322,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,
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|"
"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 };

View File

@ -36,9 +36,9 @@
#include "tasmota_version.h" // Tasmota version information
#include "tasmota.h" // Enumeration used in my_user_config.h
#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
#endif // USE_MQTT_TLS
#endif // USE_TLS
#include "tasmota_globals.h" // Function prototypes and global configuration
#include "i18n.h" // Language support configured by my_user_config.h
#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 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)
float global_temperature = 9999; // 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_pressure = 0; // Provide a global pressure to be used by some sensors
float global_temperature = NAN; // Provide a global temperature 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.0f; // Provide a global pressure to be used by some sensors
uint16_t tele_period = 9999; // Tele period timer
uint16_t blink_counter = 0; // Number of blink cycles
uint16_t seriallog_timer = 0; // Timer to disable Seriallog
@ -205,7 +205,7 @@ void setup(void) {
#endif
#endif
global_state.data = 3; // Init global state (wifi_down, mqtt_down) to solve possible network issues
global_state.data = 0xF; // Init global state (wifi_down, mqtt_down) to solve possible network issues
RtcRebootLoad();
if (!RtcRebootValid()) {
@ -278,12 +278,8 @@ void setup(void) {
#endif
}
if (RtcReboot.fast_reboot_count > Settings.param[P_BOOT_LOOP_OFFSET] +4) { // Restarted 6 times
#ifdef ESP8266
Settings.module = SONOFF_BASIC; // Reset module to Sonoff Basic
// Settings.last_module = SONOFF_BASIC;
#else // ESP32
Settings.module = WEMOS; // Reset module to Wemos
#endif // ESP8266 - ESP32
Settings.module = Settings.fallback_module; // Reset module to fallback module
// Settings.last_module = Settings.fallback_module;
}
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION D_LOG_SOME_SETTINGS_RESET " (%d)"), RtcReboot.fast_reboot_count);
}
@ -322,6 +318,11 @@ void setup(void) {
XdrvCall(FUNC_INIT);
XsnsCall(FUNC_INIT);
#ifdef USE_SCRIPT
Run_Scripter(">BS",3,0);
#endif
rules_flag.system_init = 1;
}
void BacklogLoop(void) {
@ -411,7 +412,7 @@ void loop(void) {
if (my_activity < (uint32_t)ssleep) {
SleepDelay((uint32_t)ssleep - my_activity); // Provide time for background tasks like wifi
} else {
if (global_state.wifi_down) {
if (global_state.network_down) {
SleepDelay(my_activity /2); // If wifi down and my_activity > setoption36 then force loop delay to 1/3 of my_activity period
}
}

View File

@ -21,9 +21,8 @@
// Please use fingerprint validation instead
// 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
*
@ -35,7 +34,7 @@
* 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,
0x02, 0x55, 0x53, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04, 0x0A,
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
};
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,
0x83, 0xB3, 0x68, 0x63, 0x30, 0xEA, 0xD7, 0x35, 0x26, 0x19, 0x25, 0xE1,
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
};
static const unsigned char TA0_RSA_E[] = {
static const unsigned char LetsEncrypt_RSA_E[] = {
0x01, 0x00, 0x01
};
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_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
(unsigned char *)LetsEncrypt_RSA_N, sizeof LetsEncrypt_RSA_N,
(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
*
@ -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,
0x02, 0x55, 0x53, 0x31, 0x0F, 0x30, 0x0D, 0x06, 0x03, 0x55, 0x04, 0x0A,
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
};
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,
0x50, 0x74, 0x7D, 0x6E, 0xD8, 0xD7, 0x88, 0x76, 0xF4, 0x99, 0x68, 0xF7,
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
};
static const unsigned char PROGMEM TA0_RSA_E[] = {
static const unsigned char PROGMEM AmazonRootCA1_RSA_E[] = {
0x01, 0x00, 0x01
};
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_KEYTYPE_RSA,
{ .rsa = {
(unsigned char *)TA0_RSA_N, sizeof TA0_RSA_N,
(unsigned char *)TA0_RSA_E, sizeof TA0_RSA_E,
(unsigned char *)AmazonRootCA1_RSA_N, sizeof AmazonRootCA1_RSA_N,
(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

@ -152,9 +152,10 @@
#define USE_HM10 // (ESP8266 only) Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
//#define USE_MI_ESP32 // (ESP32 only) Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
//#define USE_TASMOTA_SLAVE // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
//#define USE_TASMOTA_CLIENT // 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_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_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
@ -167,7 +168,7 @@
#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code)
//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+3k1 code)
//#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter (+2k code)
//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry
//#define USE_TELEINFO // Add support for French Energy Provider metering telemetry (+5k2 code, +168 RAM + SmartMeter LinkedList Values RAM)
#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
#define USE_MAX31855 // Add support for MAX31855 K-Type thermocouple sensor using softSPI
@ -175,6 +176,7 @@
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram)
#define USE_IR_RECEIVE // Support for IR receiver (+5k5 code, 264 iram)
#define USE_LMT01 // Add support for TI LMT01 temperature sensor, count pulses on single GPIO (+0k5 code)
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code)
#define USE_HX711 // Add support for HX711 load cell (+1k5 code)
@ -381,7 +383,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
//#define USE_DHT // Add support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor
@ -486,7 +488,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
//#undef USE_ENERGY_SENSOR // Disable energy sensors
@ -613,7 +615,7 @@
#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code)
#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash)
#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7)
#undef USE_TASMOTA_SLAVE // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem)
#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code)
#undef USE_ENERGY_SENSOR // Disable energy sensors

View File

@ -43,6 +43,16 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c
extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end);
extern "C" void resetPins();
#ifdef ESP32
#ifdef USE_ETHERNET
IPAddress EthernetLocalIP(void);
char* EthernetHostname(void);
String EthernetMacAddress(void);
#endif
#endif // ESP32
/*********************************************************************************************\
* Preconfigured configurations
\*********************************************************************************************/
@ -59,6 +69,18 @@ extern "C" void resetPins();
#ifdef USE_EMULATION_WEMO
#define USE_EMULATION
#endif
// Convert legacy slave to client
#ifdef USE_TASMOTA_SLAVE
#define USE_TASMOTA_CLIENT
#endif
#ifdef USE_TASMOTA_SLAVE_FLASH_SPEED
#define USE_TASMOTA_CLIENT_FLASH_SPEED USE_TASMOTA_SLAVE_FLASH_SPEED
#endif
#ifdef USE_TASMOTA_SLAVE_SERIAL_SPEED
#define USE_TASMOTA_CLIENT_SERIAL_SPEED USE_TASMOTA_SLAVE_SERIAL_SPEED
#endif
// See https://github.com/esp8266/Arduino/pull/4889
#undef NO_EXTRA_4K_HEAP // Allocate 4k heap for WPS in ESP8166/Arduino core v2.4.2 (was always allocated in previous versions)
@ -88,7 +110,7 @@ extern "C" void resetPins();
const uint16_t WEB_LOG_SIZE = 4000; // Max number of characters in weblog
#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."
#endif
@ -277,6 +299,9 @@ const char kWebColors[] PROGMEM =
#ifndef MODULE
#define MODULE SONOFF_BASIC // [Module] Select default model
#endif
#ifndef FALLBACK_MODULE
#define FALLBACK_MODULE SONOFF_BASIC // [Module2] Select default module on fast reboot where USER_MODULE is user template
#endif
#ifndef ARDUINO_ESP8266_RELEASE
#define ARDUINO_CORE_RELEASE "STAGE"
@ -291,6 +316,9 @@ const char kWebColors[] PROGMEM =
#ifndef MODULE
#define MODULE WEMOS // [Module] Select default model
#endif
#ifndef FALLBACK_MODULE
#define FALLBACK_MODULE WEMOS // [Module2] Select default module on fast reboot where USER_MODULE is user template
#endif
#ifndef ARDUINO_ESP32_RELEASE
#define ARDUINO_CORE_RELEASE "STAGE"

View File

@ -137,8 +137,8 @@ enum UserSelectablePins {
GPIO_TUYA_RX, // Tuya Serial interface
GPIO_MGC3130_XFER, // MGC3130 Transfer
GPIO_MGC3130_RESET, // MGC3130 Reset
GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
GPIO_SSPI_MISO, // Software SPI Master Input Client Output
GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
GPIO_SSPI_SCLK, // Software SPI Serial Clock
GPIO_SSPI_CS, // Software SPI Chip Select
GPIO_SSPI_DC, // Software SPI Data or Command
@ -210,10 +210,10 @@ enum UserSelectablePins {
GPIO_SM2135_DAT, // SM2135 Dat
GPIO_DEEPSLEEP, // Kill switch for deepsleep
GPIO_EXS_ENABLE, // EXS MCU Enable
GPIO_TASMOTASLAVE_TXD, // Slave TX
GPIO_TASMOTASLAVE_RXD, // Slave RX
GPIO_TASMOTASLAVE_RST, // Slave Reset Pin
GPIO_TASMOTASLAVE_RST_INV, // Slave Reset Inverted
GPIO_TASMOTACLIENT_TXD, // Client TX
GPIO_TASMOTACLIENT_RXD, // Client RX
GPIO_TASMOTACLIENT_RST, // Client Reset Pin
GPIO_TASMOTACLIENT_RST_INV, // Client Reset Inverted
GPIO_HPMA_RX, // Honeywell HPMA115S0 Serial interface
GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
GPIO_GPS_RX, // GPS serial interface
@ -234,8 +234,11 @@ enum UserSelectablePins {
GPIO_BOILER_OT_TX, // OpenTherm Boiler TX pin
GPIO_WINDMETER_SPEED, // WindMeter speed counter pin
GPIO_BL0940_RX, // BL0940 serial interface
GPIO_TELEINFO_RX, // BL0940 serial interface
GPIO_TELEINFO_ENABLE, // BL0940 serial interface
GPIO_TCP_TX, // TCP Serial bridge
GPIO_TCP_RX, // TCP Serial bridge
GPIO_TELEINFO_RX, // TELEINFO serial interface
GPIO_TELEINFO_ENABLE,// TELEINFO Enable PIN
GPIO_LMT01, // LMT01 input counting pin
GPIO_SENSOR_END };
// Programmer selectable GPIO functionality
@ -314,7 +317,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "i|"
D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "i|"
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
D_SENSOR_DS18X20 "o|" D_SENSOR_DHT11 "o|"
@ -327,7 +330,9 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BOILER_OT_RX "|" D_SENSOR_BOILER_OT_TX "|"
D_SENSOR_WINDMETER_SPEED "|"
D_SENSOR_BL0940_RX "|"
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|"
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|"
D_SENSOR_LMT01_PULSE
;
const char kSensorNamesFixed[] PROGMEM =
@ -427,8 +432,8 @@ const uint8_t kGpioNiceList[] PROGMEM = {
#ifdef USE_SPI
GPIO_SPI_CS, // SPI Chip Select
GPIO_SPI_DC, // SPI Data Direction
GPIO_SSPI_MISO, // Software SPI Master Input Slave Output
GPIO_SSPI_MOSI, // Software SPI Master Output Slave Input
GPIO_SSPI_MISO, // Software SPI Master Input Client Output
GPIO_SSPI_MOSI, // Software SPI Master Output Client Input
GPIO_SSPI_SCLK, // Software SPI Serial Clock
GPIO_SSPI_CS, // Software SPI Chip Select
GPIO_SSPI_DC, // Software SPI Data or Command
@ -447,6 +452,9 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_DSB, // Single wire DS18B20 or DS18S20
GPIO_DSB_OUT, // Pseudo Single wire DS18B20 or DS18S20
#endif
#ifdef USE_LMT01 // LMT01, count pulses on GPIO
GPIO_LMT01,
#endif
// Light
#ifdef USE_LIGHT
@ -577,6 +585,10 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_SBR_TX, // Serial Bridge Serial interface
GPIO_SBR_RX, // Serial Bridge Serial interface
#endif
#ifdef USE_TCP_BRIDGE
GPIO_TCP_TX, // TCP Serial bridge
GPIO_TCP_RX, // TCP Serial bridge
#endif
#ifdef USE_ZIGBEE
GPIO_ZIGBEE_TX, // Zigbee Serial interface
GPIO_ZIGBEE_RX, // Zigbee Serial interface
@ -618,11 +630,11 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_PN532_TXD, // PN532 HSU Tx
GPIO_PN532_RXD, // PN532 HSU Rx
#endif
#ifdef USE_TASMOTA_SLAVE
GPIO_TASMOTASLAVE_TXD, // Tasmota Slave TX
GPIO_TASMOTASLAVE_RXD, // Tasmota Slave RX
GPIO_TASMOTASLAVE_RST, // Tasmota Slave Reset
GPIO_TASMOTASLAVE_RST_INV, // Tasmota Slave Reset Inverted
#ifdef USE_TASMOTA_CLIENT
GPIO_TASMOTACLIENT_TXD, // Tasmota Client TX
GPIO_TASMOTACLIENT_RXD, // Tasmota Client RX
GPIO_TASMOTACLIENT_RST, // Tasmota Client Reset
GPIO_TASMOTACLIENT_RST_INV, // Tasmota Client Reset Inverted
#endif
#ifdef USE_RDM6300
GPIO_RDM6300_RX,
@ -689,7 +701,6 @@ const uint8_t kGpioNiceList[] PROGMEM = {
GPIO_TELEINFO_RX,
GPIO_TELEINFO_ENABLE,
#endif
};
/********************************************************************************************/
@ -778,7 +789,7 @@ enum SupportedModules {
SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH,
OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4,
OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1,
SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, DENKY,
SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1,
MAXMODULE};
#define USER_MODULE 255
@ -791,7 +802,7 @@ const char kModuleNames[] PROGMEM =
"Sonoff S31|Zengge WF017|Sonoff Pow R2|Sonoff iFan02|BlitzWolf SHP|Shelly 1|Shelly 2|Xiaomi Philips|Neo Coolcam|ESP Switch|"
"OBI Socket|Teckin|AplicWDP303075|Tuya MCU|Gosund SP1 v23|ARMTR Dimmer|SK03 Outdoor|PS-16-DZ|Teckin US|Manzoku strip|"
"OBI Socket 2|YTF IR Bridge|Digoo DG-SP202|KA10|Luminea ZX2820|Mi Desk Lamp|SP10|WAGA CHCZ02MB|SYF05|Sonoff L1|"
"Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1|Denky (Teleinfo)"
"Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1"
;
const uint8_t kModuleNiceList[] PROGMEM = {
@ -2174,26 +2185,6 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status
0, 0, 0, 0
},
{ // Denky (Teleinfo) Any ESP8266 device
GPIO_WS2812, // GPIO00 WS2812 RGB LED
GPIO_USER, // GPIO01 TX Serial RXD
GPIO_USER, // GPIO02 D4 Wemos DHT Shield
GPIO_TELEINFO_RX, // GPIO03 Smart Meter RX Serial
GPIO_I2C_SDA, // GPIO04 D2 Wemos I2C SDA
GPIO_I2C_SCL, // GPIO05 D1 Wemos I2C SCL
// GPIO06 (SD_CLK Flash)
// GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT)
// GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT)
GPIO_USER, // GPIO09 (SD_DATA2 Flash QIO or ESP8285)
GPIO_USER, // GPIO10 (SD_DATA3 Flash QIO or ESP8285)
// GPIO11 (SD_CMD Flash)
GPIO_USER, // GPIO12 D6
GPIO_USER, // GPIO13 D7
GPIO_USER, // GPIO14 D5
GPIO_USER, // GPIO15 D8
GPIO_USER, // GPIO16 D0 Wemos Wake
ADC0_USER // ADC0 A0 Analog input
},
{ // SONOFF_IFAN03 - Sonoff iFan03 (ESP8285)
GPIO_KEY1, // GPIO00 WIFI_KEY0 Button 1
GPIO_TXD, // GPIO01 ESP_TXD Serial RXD connection to P0.5 of RF microcontroller
@ -2278,10 +2269,8 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status
0, 0, 0, 0
}
};
#endif // ESP8266
#ifdef ESP32

View File

@ -102,8 +102,8 @@ enum UserSelectablePins {
GPIO_SM2135_CLK, GPIO_SM2135_DAT, // SM2135 PWM controller
GPIO_DEEPSLEEP, // Kill switch for deepsleep
GPIO_EXS_ENABLE, // EXS MCU Enable
GPIO_TASMOTASLAVE_TXD, GPIO_TASMOTASLAVE_RXD, // Slave Serial interface
GPIO_TASMOTASLAVE_RST, GPIO_TASMOTASLAVE_RST_INV, // Slave Reset
GPIO_TASMOTACLIENT_TXD, GPIO_TASMOTACLIENT_RXD, // Client Serial interface
GPIO_TASMOTACLIENT_RST, GPIO_TASMOTACLIENT_RST_INV, // Client Reset
GPIO_HPMA_RX, GPIO_HPMA_TX, // Honeywell HPMA115S0 Serial interface
GPIO_GPS_RX, GPIO_GPS_TX, // GPS Serial interface
GPIO_HM10_RX, GPIO_HM10_TX, // HM10-BLE-Mijia-bridge Serial interface
@ -133,6 +133,7 @@ enum UserSelectablePins {
GPIO_ETH_PHY_POWER, GPIO_ETH_PHY_MDC, GPIO_ETH_PHY_MDIO, // Ethernet
GPIO_TELEINFO_RX, // Teleinfo telemetry data receive pin
GPIO_TELEINFO_ENABLE, // Teleinfo Enable Receive Pin
GPIO_LMT01, // LMT01 input counting pin
GPIO_SENSOR_END };
enum ProgramSelectablePins {
@ -199,7 +200,7 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_DDSU666_TX "|" D_SENSOR_DDSU666_RX "|"
D_SENSOR_SM2135_CLK "|" D_SENSOR_SM2135_DAT "|"
D_SENSOR_DEEPSLEEP "|" D_SENSOR_EXS_ENABLE "|"
D_SENSOR_SLAVE_TX "|" D_SENSOR_SLAVE_RX "|" D_SENSOR_SLAVE_RESET "|" D_SENSOR_SLAVE_RESET "_i|"
D_SENSOR_CLIENT_TX "|" D_SENSOR_CLIENT_RX "|" D_SENSOR_CLIENT_RESET "|" D_SENSOR_CLIENT_RESET "_i|"
D_SENSOR_HPMA_RX "|" D_SENSOR_HPMA_TX "|"
D_SENSOR_GPS_RX "|" D_SENSOR_GPS_TX "|"
D_SENSOR_HM10_RX "|" D_SENSOR_HM10_TX "|"
@ -225,7 +226,8 @@ const char kSensorNames[] PROGMEM =
D_SENSOR_BL0940_RX "|"
D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|"
D_SENSOR_ETH_PHY_POWER "|" D_SENSOR_ETH_PHY_MDC "|" D_SENSOR_ETH_PHY_MDIO "|"
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE
D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|"
D_SENSOR_LMT01_PULSE
;
const char kSensorNamesFixed[] PROGMEM =
@ -269,8 +271,8 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_SPI_CLK), // SPI Clk
AGPIO(GPIO_SPI_CS), // SPI Chip Select
AGPIO(GPIO_SPI_DC), // SPI Data Direction
AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Slave Output
AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Slave Input
AGPIO(GPIO_SSPI_MISO), // Software SPI Master Input Client Output
AGPIO(GPIO_SSPI_MOSI), // Software SPI Master Output Client Input
AGPIO(GPIO_SSPI_SCLK), // Software SPI Serial Clock
AGPIO(GPIO_SSPI_CS), // Software SPI Chip Select
AGPIO(GPIO_SSPI_DC), // Software SPI Data or Command
@ -293,6 +295,9 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_DSB), // Single wire DS18B20 or DS18S20
AGPIO(GPIO_DSB_OUT), // Pseudo Single wire DS18B20 or DS18S20
#endif
#ifdef USE_LMT01
AGPIO(GPIO_LMT01), // LMT01, count pulses on GPIO
#endif
// Light
#ifdef USE_LIGHT
@ -468,11 +473,11 @@ const uint16_t kGpioNiceList[] PROGMEM = {
AGPIO(GPIO_PN532_TXD), // PN532 HSU Tx
AGPIO(GPIO_PN532_RXD), // PN532 HSU Rx
#endif
#ifdef USE_TASMOTA_SLAVE
AGPIO(GPIO_TASMOTASLAVE_TXD), // Tasmota Slave TX
AGPIO(GPIO_TASMOTASLAVE_RXD), // Tasmota Slave RX
AGPIO(GPIO_TASMOTASLAVE_RST), // Tasmota Slave Reset
AGPIO(GPIO_TASMOTASLAVE_RST_INV), // Tasmota Slave Reset Inverted
#ifdef USE_TASMOTA_CLIENT
AGPIO(GPIO_TASMOTACLIENT_TXD), // Tasmota Client TX
AGPIO(GPIO_TASMOTACLIENT_RXD), // Tasmota Client RX
AGPIO(GPIO_TASMOTACLIENT_RST), // Tasmota Client Reset
AGPIO(GPIO_TASMOTACLIENT_RST_INV), // Tasmota Client Reset Inverted
#endif
#ifdef USE_RDM6300
AGPIO(GPIO_RDM6300_RX),
@ -685,12 +690,12 @@ const mytmplt kModules PROGMEM =
/*********************************************************************************************\
Known templates
{"NAME":"AITHINKER CAM","GPIO":[4992,65504,65504,65504,65504,5088,65504,65504,65504,65504,65504,65504,65504,65504,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,65504,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
{"NAME":"Olimex ESP32-PoE","GPIO":[65504,65504,65504,65504,65504,65504,0,0,5536,65504,65504,65504,65504,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,65504,65504,65504,65504,65504,0,0,65504],"FLAG":0,"BASE":1}
{"NAME":"AITHINKER CAM","GPIO":[4992,1,1,1,1,5088,1,1,1,1,1,1,1,1,5089,5090,0,5091,5184,5152,0,5120,5024,5056,0,0,0,0,4928,1,5094,5095,5092,0,0,5093],"FLAG":0,"BASE":1}
{"NAME":"Olimex ESP32-PoE","GPIO":[1,1,1,1,1,1,0,0,5536,1,1,1,1,0,5600,0,0,0,0,5568,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
{"NAME":"wESP32","GPIO":[1,1,1,1,1,1,0,0,0,1,1,1,5568,5600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
\*********************************************************************************************/
#endif // ESP32
#endif // _TASMOTA_TEMPLATE_ESP32_H_

View File

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

View File

@ -44,7 +44,7 @@ const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 28000; // milliseconds - Allow
uint8_t *efm8bb1_update = nullptr;
#endif // USE_RF_FLASH
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTASLAVE };
enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT };
static const char * HEADER_KEYS[] = { "User-Agent", };
@ -868,10 +868,16 @@ void StartWebserver(int type, IPAddress ipweb)
if (Web.state != type) {
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
if(ipv6_addr!="") AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str(),ipv6_addr.c_str());
else AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str());
if (ipv6_addr!="") {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "),
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str(), ipv6_addr.c_str());
} else {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
}
#else
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str());
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"),
NetworkHostname(), (Mdns.begun) ? ".local" : "", ipweb.toString().c_str());
#endif // LWIP_IPV6 = 1
rules_flag.http_init = 1;
}
@ -1151,8 +1157,8 @@ void WSContentSendStyle_P(const char* formatP, ...)
bool lip = (static_cast<uint32_t>(WiFi.localIP()) != 0);
bool sip = (static_cast<uint32_t>(WiFi.softAPIP()) != 0);
WSContentSend_P(PSTR("<h4>%s%s (%s%s%s)</h4>"), // tasmota.local (192.168.2.12, 192.168.4.1)
my_hostname,
(Wifi.mdns_begun) ? ".local" : "",
NetworkHostname(),
(Mdns.begun) ? ".local" : "",
(lip) ? WiFi.localIP().toString().c_str() : "",
(lip && sip) ? ", " : "",
(sip) ? WiFi.softAPIP().toString().c_str() : "");
@ -2016,8 +2022,8 @@ void ModuleSaveSettings(void)
/*-------------------------------------------------------------------------------------------*/
const char kUnescapeCode[] = "&><\"\'";
const char kEscapeCode[] PROGMEM = "&amp;|&gt;|&lt;|&quot;|&apos;";
const char kUnescapeCode[] = "&><\"\'\\";
const char kEscapeCode[] PROGMEM = "&amp;|&gt;|&lt;|&quot;|&apos;|&#92;";
String HtmlEscape(const String unescaped) {
char escaped[10];
@ -2321,22 +2327,6 @@ void OtherSaveSettings(void)
}
AddLog_P(LOG_LEVEL_INFO, message);
/*
// This sometimes provides intermittent watchdog
bool template_activate = Webserver->hasArg("t2"); // Try this to tackle intermittent watchdog after execution of Template command
WebGetArg("t1", tmp, sizeof(tmp));
if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
char svalue[128];
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_TEMPLATE " %s"), tmp);
ExecuteWebCommand(svalue, SRC_WEBGUI);
if (template_activate) {
snprintf_P(svalue, sizeof(svalue), PSTR(D_CMND_MODULE " 0"));
ExecuteWebCommand(svalue, SRC_WEBGUI);
}
}
// Try async execution of commands
*/
WebGetArg("t1", tmp, sizeof(tmp));
if (strlen(tmp)) { // {"NAME":"12345678901234","GPIO":[255,255,255,255,255,255,255,255,255,255,255,255,255],"FLAG":255,"BASE":255}
snprintf_P(message, sizeof(message), PSTR(D_CMND_BACKLOG " " D_CMND_TEMPLATE " %s%s"), tmp, (Webserver->hasArg("t2")) ? "; " D_CMND_MODULE " 0" : "");
@ -2471,26 +2461,42 @@ void HandleInformation(void)
WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, SettingsText(SET_FRIENDLYNAME1 +i));
}
WSContentSend_P(PSTR("}1}2&nbsp;")); // Empty line
#ifdef ESP32
#ifdef USE_ETHERNET
if (static_cast<uint32_t>(EthernetLocalIP()) != 0) {
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Mdns.begun) ? ".local" : "");
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (eth)}2%s"), EthernetLocalIP().toString().c_str());
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
}
#endif
#endif
if (Settings.flag4.network_wifi) {
int32_t rssi = WiFi.RSSI();
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WifiGetRssiAsQuality(rssi), rssi);
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "");
WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, HtmlEscape(SettingsText(SET_STASSID1 + Settings.sta_active)).c_str(), WifiGetRssiAsQuality(rssi), rssi);
WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Mdns.begun) ? ".local" : "");
#if LWIP_IPV6
String ipv6_addr = WifiGetIPv6();
if(ipv6_addr != ""){
if (ipv6_addr != "") {
WSContentSend_P(PSTR("}1 IPv6 Address }2%s"), ipv6_addr.c_str());
}
#endif
if (static_cast<uint32_t>(WiFi.localIP()) != 0) {
WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str());
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (wifi)}2%s"), WiFi.localIP().toString().c_str());
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
}
}
if (!global_state.network_down) {
WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str());
WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str());
WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str());
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str());
}
if (static_cast<uint32_t>(WiFi.softAPIP()) != 0) {
WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str());
WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str());
if ((WiFi.getMode() >= WIFI_AP) && (static_cast<uint32_t>(WiFi.softAPIP()) != 0)) {
WSContentSend_P(PSTR("}1<hr/>}2<hr/>"));
WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str());
WSContentSend_P(PSTR("}1" D_IP_ADDRESS " (AP)}2%s"), WiFi.softAPIP().toString().c_str());
WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str());
}
WSContentSend_P(PSTR("}1}2&nbsp;")); // Empty line
if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT
@ -2645,8 +2651,8 @@ void HandleUploadDone(void)
WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "</font></b><br>"), WebColor(COL_TEXT_SUCCESS));
WSContentSend_P(HTTP_MSG_RSTRT);
ShowWebSource(SRC_WEBGUI);
#ifdef USE_TASMOTA_SLAVE
if (TasmotaSlave_GetFlagFlashing()) {
#ifdef USE_TASMOTA_CLIENT
if (TasmotaClient_GetFlagFlashing()) {
restart_flag = 0;
} else { // It was a normal firmware file, or we are ready to restart device
restart_flag = 2;
@ -2659,9 +2665,9 @@ void HandleUploadDone(void)
WSContentSend_P(PSTR("</div><br>"));
WSContentSpaceButton(BUTTON_MAIN);
WSContentStop();
#ifdef USE_TASMOTA_SLAVE
if (TasmotaSlave_GetFlagFlashing()) {
TasmotaSlave_Flash();
#ifdef USE_TASMOTA_CLIENT
if (TasmotaClient_GetFlagFlashing()) {
TasmotaClient_Flash();
}
#endif
}
@ -2731,11 +2737,11 @@ void HandleUploadLoop(void)
if (Web.upload_error != 0) { return; }
} else
#endif // USE_RF_FLASH
#ifdef USE_TASMOTA_SLAVE
if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO SLAVE hex file
#ifdef USE_TASMOTA_CLIENT
if ((WEMOS == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a ARDUINO CLIENT hex file
Update.end(); // End esp8266 update session
Web.upload_file_type = UPL_TASMOTASLAVE;
Web.upload_error = TasmotaSlave_UpdateInit(); // 0
Web.upload_file_type = UPL_TASMOTACLIENT;
Web.upload_error = TasmotaClient_UpdateInit(); // 0
if (Web.upload_error != 0) { return; }
} else
#endif
@ -2799,9 +2805,9 @@ void HandleUploadLoop(void)
}
}
#endif // USE_RF_FLASH
#ifdef USE_TASMOTA_SLAVE
else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
TasmotaSlave_WriteBuffer(upload.buf, upload.currentSize);
#ifdef USE_TASMOTA_CLIENT
else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
TasmotaClient_WriteBuffer(upload.buf, upload.currentSize);
}
#endif
else { // firmware
@ -2865,10 +2871,10 @@ void HandleUploadLoop(void)
Web.upload_file_type = UPL_TASMOTA;
}
#endif // USE_RF_FLASH
#ifdef USE_TASMOTA_SLAVE
else if (UPL_TASMOTASLAVE == Web.upload_file_type) {
#ifdef USE_TASMOTA_CLIENT
else if (UPL_TASMOTACLIENT == Web.upload_file_type) {
// Done writing the hex to SPI flash
TasmotaSlave_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
TasmotaClient_SetFlagFlashing(true); // So we know on upload success page if it needs to flash hex or do a normal restart
Web.upload_file_type = UPL_TASMOTA;
}
#endif
@ -3288,7 +3294,7 @@ void CmndWebServer(void)
}
if (Settings.webserver) {
Response_P(PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
(2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str());
} else {
ResponseCmndStateText(0);
}

View File

@ -123,34 +123,6 @@ void MakeValidMqtt(uint32_t option, char* str)
}
}
#ifdef USE_DISCOVERY
#ifdef MQTT_HOST_DISCOVERY
void MqttDiscoverServer(void)
{
if (!Wifi.mdns_begun) { return; }
int n = MDNS.queryService("mqtt", "tcp"); // Search for mqtt service
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_QUERY_DONE " %d"), n);
if (n > 0) {
uint32_t i = 0; // If the hostname isn't set, use the first record found.
#ifdef MDNS_HOSTNAME
for (i = n; i > 0; i--) { // Search from last to first and use first if not found
if (!strcmp(MDNS.hostname(i).c_str(), MDNS_HOSTNAME)) {
break; // Stop at matching record
}
}
#endif // MDNS_HOSTNAME
SettingsUpdateText(SET_MQTT_HOST, MDNS.IP(i).toString().c_str());
Settings.mqtt_port = MDNS.port(i);
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_MQTT_SERVICE_FOUND " %s, " D_IP_ADDRESS " %s, " D_PORT " %d"), MDNS.hostname(i).c_str(), SettingsText(SET_MQTT_HOST), Settings.mqtt_port);
}
}
#endif // MQTT_HOST_DISCOVERY
#endif // USE_DISCOVERY
/*********************************************************************************************\
* MQTT driver specific code need to provide the following functions:
*
@ -539,10 +511,10 @@ void MqttConnected(void)
if (Settings.webserver) {
#if LWIP_IPV6
Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str(),WifiGetIPv6().c_str());
(2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str());
#else
Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"),
(2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str());
(2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str());
#endif // LWIP_IPV6 = 1
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2"));
}

View File

@ -459,7 +459,12 @@ void EnergyEverySecond(void)
{
// Overtemp check
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);
}
}
@ -1137,6 +1142,9 @@ bool Xdrv03(uint8_t function)
case FUNC_EVERY_250_MSECOND:
XnrgCall(FUNC_EVERY_250_MSECOND);
break;
case FUNC_EVERY_SECOND:
XnrgCall(FUNC_EVERY_SECOND);
break;
case FUNC_SERIAL:
result = XnrgCall(FUNC_SERIAL);
break;

View File

@ -1555,10 +1555,10 @@ void LightState(uint8_t append)
if (!Light.pwm_multi_channels) {
if (unlinked) {
// RGB and W are unlinked, we display the second Power/Dimmer
ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"
",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "%d\":%d"),
Light.device, GetStateText(Light.power & 1), Light.device, light_state.getDimmer(1),
Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), Light.device + 1, light_state.getDimmer(2));
ResponseAppend_P(PSTR("\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "1\":%d"
",\"" D_RSLT_POWER "%d\":\"%s\",\"" D_CMND_DIMMER "2\":%d"),
Light.device, GetStateText(Light.power & 1), light_state.getDimmer(1),
Light.device + 1, GetStateText(Light.power & 2 ? 1 : 0), light_state.getDimmer(2));
} else {
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),

View File

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

View File

@ -26,7 +26,6 @@ uses about 17 k of flash
to do
optimize code for space
g:var gloabal vars (via udp broadcast)
remarks
@ -68,6 +67,8 @@ keywords if then else endif, or, and are better readable for beginners (others m
uint32_t EncodeLightId(uint8_t relay_id);
uint32_t DecodeLightId(uint32_t hue_id);
// solve conficting defines
// highest priority
#ifdef USE_SCRIPT_FATFS
@ -119,6 +120,31 @@ uint32_t DecodeLightId(uint32_t hue_id);
#endif
#endif // USE_UNISHOX_COMPRESSION
#ifdef USE_SCRIPT_TIMER
#include <Ticker.h>
Ticker Script_ticker1;
Ticker Script_ticker2;
Ticker Script_ticker3;
Ticker Script_ticker4;
void Script_ticker1_end(void) {
Script_ticker1.detach();
Run_Scripter(">ti1", 4,0);
}
void Script_ticker2_end(void) {
Script_ticker2.detach();
Run_Scripter(">ti2", 4,0);
}
void Script_ticker3_end(void) {
Script_ticker3.detach();
Run_Scripter(">ti3", 4,0);
}
void Script_ticker4_end(void) {
Script_ticker4.detach();
Run_Scripter(">ti4", 4,0);
}
#endif
#if defined(LITTLEFS_SCRIPT_SIZE) || (USE_SCRIPT_FATFS==-1)
#ifdef ESP32
@ -237,7 +263,11 @@ extern VButton *buttons[MAXBUTTONS];
#endif
typedef union {
#ifdef USE_SCRIPT_GLOBVARS
uint16_t data;
#else
uint8_t data;
#endif
struct {
uint8_t is_string : 1; // string or number
uint8_t is_permanent : 1;
@ -247,6 +277,9 @@ typedef union {
uint8_t settable : 1;
uint8_t is_filter : 1;
uint8_t constant : 1;
#ifdef USE_SCRIPT_GLOBVARS
uint8_t global : 1;
#endif
};
} SCRIPT_TYPE;
@ -276,6 +309,32 @@ typedef union {
};
} 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
// global memory
struct SCRIPT_MEM {
@ -308,12 +367,19 @@ struct SCRIPT_MEM {
uint8_t script_sd_found;
char flink[2][14];
#endif
#ifdef USE_SCRIPT_GLOBVARS
UDP_FLAGS udp_flags;
#endif
} glob_script_mem;
#ifdef USE_SCRIPT_GLOBVARS
IPAddress last_udp_ip;
#endif
int16_t last_findex;
uint8_t tasm_cmd_activ=0;
uint8_t fast_script=0;
uint8_t glob_script=0;
uint32_t script_lastmillis;
@ -331,7 +397,7 @@ void ScriptEverySecond(void) {
if (bitRead(Settings.rule_enabled, 0)) {
struct T_INDEX *vtp=glob_script_mem.type;
float delta=(millis()-script_lastmillis)/1000;
float delta=(millis()-script_lastmillis)/1000.0;
script_lastmillis=millis();
for (uint8_t count=0; count<glob_script_mem.numvars; count++) {
if (vtp[count].bits.is_timer) {
@ -436,6 +502,16 @@ char *script;
} else {
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)==':') {
uint8_t flg=*lp;
lp+=2;
@ -703,10 +779,112 @@ char *script;
// store start of actual program here
glob_script_mem.scriptptr=lp-1;
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;
}
#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.network_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_WS2812
void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
@ -723,16 +901,7 @@ void ws2812_set_array(float *array ,uint32_t len, uint32_t offset) {
#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) {
uint8_t ind[len];
@ -1011,6 +1180,37 @@ uint32_t MeasurePulseTime(int32_t in) {
}
#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
// no flash strings here for performance reasons!!!
char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,JsonObject *jo) {
@ -1703,6 +1903,20 @@ chknext:
if (sp) strlcpy(sp,SettingsText(SET_MQTT_GRP_TOPIC),glob_script_mem.max_ssize);
goto strexit;
}
#ifdef SCRIPT_GET_HTTPS_JP
if (!strncmp(vname,"gjp(",4)) {
char host[SCRIPT_MAXSSIZE];
lp=GetStringResult(lp+4,OPER_EQU,host,0);
SCRIPT_SKIP_SPACES
char path[SCRIPT_MAXSSIZE];
lp=GetStringResult(lp,OPER_EQU,path,0);
fvar=call2https(host,path);
lp++;
len=0;
goto exit;
}
#endif
break;
case 'h':
if (!strncmp(vname,"hours",5)) {
@ -1765,12 +1979,40 @@ chknext:
len=0;
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;
case 'l':
if (!strncmp(vname,"lip",3)) {
if (sp) strlcpy(sp,(const char*)WiFi.localIP().toString().c_str(),glob_script_mem.max_ssize);
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)) {
fvar=glob_script_mem.script_loglevel;
tind->index=SCRIPT_LOGLEVEL;
@ -2209,6 +2451,41 @@ chknext:
if (sp) strlcpy(sp,SettingsText(SET_MQTT_TOPIC),glob_script_mem.max_ssize);
goto strexit;
}
#ifdef USE_SCRIPT_TIMER
if (!strncmp(vname,"ts1(",4)) {
lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
if (fvar<10) fvar=10;
Script_ticker1.attach_ms(fvar, Script_ticker1_end);
lp++;
len=0;
goto exit;
}
if (!strncmp(vname,"ts2(",4)) {
lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
if (fvar<10) fvar=10;
Script_ticker2.attach_ms(fvar, Script_ticker2_end);
lp++;
len=0;
goto exit;
}
if (!strncmp(vname,"ts3(",4)) {
lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
if (fvar<10) fvar=10;
Script_ticker3.attach_ms(fvar, Script_ticker3_end);
lp++;
len=0;
goto exit;
}
if (!strncmp(vname,"ts4(",4)) {
lp=GetNumericResult(lp+4,OPER_EQU,&fvar,0);
if (fvar<10) fvar=10;
Script_ticker4.attach_ms(fvar, Script_ticker4_end);
lp++;
len=0;
goto exit;
}
#endif // USE_SCRIPT_TIMER
#ifdef USE_DISPLAY
#ifdef USE_TOUCH_BUTTONS
if (!strncmp(vname,"tbut[",5)) {
@ -3167,7 +3444,7 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line;
#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);
#endif
@ -3382,8 +3659,16 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
}
goto next_line;
} else {
char *vnp=lp;
lp=isvar(lp,&vtype,&ind,&sysvar,0,0);
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
globvindex=ind.index; // save destination var index here
globaindex=last_findex;
@ -3451,6 +3736,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
}
// var was changed
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 (globaindex>=0) {
Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar);
@ -3492,6 +3782,11 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
if (!glob_script_mem.var_not_found) {
// var was changed
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) {
strlcpy(glob_script_mem.glob_snp+(sindex*glob_script_mem.max_ssize),str,glob_script_mem.max_ssize);
} else if (lastop==OPER_PLSEQU) {
@ -3979,8 +4274,7 @@ void ListDir(char *path, uint8_t depth) {
char path[48];
void Script_FileUploadConfiguration(void)
{
void Script_FileUploadConfiguration(void) {
uint8_t depth=0;
strcpy(path,"/");
@ -3995,17 +4289,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);
WSContentSendStyle();
WSContentSend_P(HTTP_FORM_FILE_UPLOAD,D_SDCARD_DIR);
@ -4023,13 +4306,22 @@ void Script_FileUploadConfiguration(void)
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;
void script_upload(void) {
//AddLog_P(LOG_LEVEL_INFO, PSTR("HTP: file upload"));
HTTPUpload& upload = Webserver->upload();
if (upload.status == UPLOAD_FILE_START) {
char npath[48];
@ -4601,9 +4893,11 @@ void Script_Check_Hue(String *response) {
}
else {
if (hue_devs>0) *response+=",\"";
else *response+="\"";
}
*response+=String(EncodeLightId(hue_devs+devices_present+1))+"\":";
Script_HueStatus(response,hue_devs);
//AddLog_P2(LOG_LEVEL_INFO, PSTR("Hue: %s - %d "),response->c_str(), hue_devs);
}
hue_devs++;
@ -5902,6 +6196,62 @@ uint32_t scripter_create_task(uint32_t num, uint32_t time, uint32_t core) {
#endif // USE_SCRIPT_TASK
#endif // ESP32
#ifdef SCRIPT_GET_HTTPS_JP
#ifdef ESP8266
#include "WiFiClientSecureLightBearSSL.h"
#else
#include <WiFiClientSecure.h>
#endif
// get tesla powerwall info page json string
uint32_t call2https(const char *host, const char *path) {
if (global_state.wifi_down) return 1;
uint32_t status=0;
#ifdef ESP32
WiFiClientSecure *httpsClient;
httpsClient = new WiFiClientSecure;
#else
BearSSL::WiFiClientSecure_light *httpsClient;
httpsClient = new BearSSL::WiFiClientSecure_light(1024, 1024);
#endif
httpsClient->setTimeout(1500);
int retry = 0;
String result;
while ((!httpsClient->connect(host, 443)) && (retry < 5)) {
delay(100);
retry++;
}
if (retry == 5) {
return 2;
}
String request = String("GET ") + path +
" HTTP/1.1\r\n" +
"Host: " + host +
"\r\n" + "Connection: close\r\n\r\n";
httpsClient->print(request);
while (httpsClient->connected()) {
String line = httpsClient->readStringUntil('\n');
if (line == "\r") {
break;
}
}
while (httpsClient->available()) {
String line = httpsClient->readStringUntil('\n');
if (line!="") {
result += line;
}
}
httpsClient->stop();
Run_Scripter(">jp",3,(char*)result.c_str());
return 0;
}
#endif // SCRIPT_GET_HTTPS_JP
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
@ -6139,6 +6489,12 @@ bool Xdrv10(uint8_t function)
break;
#endif
#ifdef USE_SCRIPT_GLOBVARS
case FUNC_LOOP:
Script_PollUdp();
break;
#endif
}
return result;
}

View File

@ -114,6 +114,7 @@ device_parameters_t device_param[] = {
{ KNX_SLOT3 , false, false, KNX_Empty },
{ KNX_SLOT4 , false, false, KNX_Empty },
{ KNX_SLOT5 , false, false, KNX_Empty },
{ KNX_SCENE , false, false, KNX_Empty },
{ KNX_Empty, false, false, KNX_Empty}
};
@ -149,6 +150,7 @@ const char * device_param_ga[] = {
D_KNX_TX_SLOT " 3",
D_KNX_TX_SLOT " 4",
D_KNX_TX_SLOT " 5",
D_KNX_TX_SCENE ,
nullptr
};
@ -184,6 +186,7 @@ const char *device_param_cb[] = {
D_KNX_RX_SLOT " 3",
D_KNX_RX_SLOT " 4",
D_KNX_RX_SLOT " 5",
D_KNX_RX_SCENE ,
nullptr
};
@ -196,12 +199,14 @@ const char *device_param_cb[] = {
#define D_CMND_KNX_PA "_PA"
#define D_CMND_KNX_GA "_GA"
#define D_CMND_KNX_CB "_CB"
#define D_CMND_KNXTXSCENE "Tx_Scene"
const char kKnxCommands[] PROGMEM = D_PRFX_KNX "|" // Prefix
D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB ;
D_CMND_KNXTXCMND "|" D_CMND_KNXTXVAL "|" D_CMND_KNX_ENABLED "|" D_CMND_KNX_ENHANCED "|" D_CMND_KNX_PA "|" D_CMND_KNX_GA "|" D_CMND_KNX_CB "|" D_CMND_KNXTXSCENE ;
void (* const KnxCommand[])(void) PROGMEM = {
&CmndKnxTxCmnd, &CmndKnxTxVal, &CmndKnxEnabled, &CmndKnxEnhanced, &CmndKnxPa, &CmndKnxGa, &CmndKnxCb };
&CmndKnxTxCmnd, &CmndKnxTxVal, &CmndKnxEnabled, &CmndKnxEnhanced, &CmndKnxPa, &CmndKnxGa, &CmndKnxCb, &CmndKnxTxScene };
uint8_t KNX_GA_Search( uint8_t param, uint8_t start = 0 )
{
@ -518,6 +523,7 @@ void KNX_INIT(void)
device_param[KNX_SLOT3-1].show = true;
device_param[KNX_SLOT4-1].show = true;
device_param[KNX_SLOT5-1].show = true;
device_param[KNX_SCENE-1].show = true;
#endif
// Delete from KNX settings all configuration is not anymore related to this device
@ -557,6 +563,10 @@ void KNX_CB_Action(message_t const &msg, void *arg)
if (msg.data_len == 1) {
// COMMAND
sprintf(tempchar,"%d",msg.data[0]);
} else if (chan->type == KNX_SCENE) {
// VALUE
uint8_t tempvar = knx.data_to_1byte_uint(msg.data);
dtostrfd(tempvar,2,tempchar);
} else {
// VALUE
float tempvar = knx.data_to_2byte_float(msg.data);
@ -602,6 +612,18 @@ void KNX_CB_Action(message_t const &msg, void *arg)
}
}
}
else if (chan->type == KNX_SCENE) // KNX RX SCENE SLOT (write command)
{
if (!toggle_inhibit) {
char command[25];
// Value received
snprintf_P(command, sizeof(command), PSTR("event KNX_SCENE=%s"), tempchar);
ExecuteCommand(command, SRC_KNX);
if (Settings.flag.knx_enable_enhancement) {
toggle_inhibit = TOGGLE_INHIBIT_TIME;
}
}
}
#endif
break;
@ -1054,6 +1076,31 @@ void CmndKnxTxVal(void)
}
}
void CmndKnxTxScene(void)
{
if ( (XdrvMailbox.data_len > 0) && Settings.flag.knx_enabled ) {
// XdrvMailbox.payload <- scene number to send
uint8_t i = KNX_GA_Search(KNX_SCENE);
if ( i != KNX_Empty ) {
KNX_addr.value = Settings.knx_GA_addr[i];
uint8_t tempvar = TextToInt(XdrvMailbox.data);
dtostrfd(tempvar,0,XdrvMailbox.data);
knx.write_1byte_uint(KNX_addr, tempvar);
if (Settings.flag.knx_enable_enhancement) {
knx.write_1byte_uint(KNX_addr, tempvar);
knx.write_1byte_uint(KNX_addr, tempvar);
}
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_KNX "%s = %s " D_SENT_TO " %d.%d.%d"),
device_param_ga[KNX_SCENE-1], XdrvMailbox.data,
KNX_addr.ga.area, KNX_addr.ga.line, KNX_addr.ga.member);
ResponseCmndIdxChar (XdrvMailbox.data);
}
}
}
void CmndKnxEnabled(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
@ -1208,7 +1255,7 @@ bool Xdrv11(uint8_t function)
bool result = false;
switch (function) {
case FUNC_LOOP:
if (!global_state.wifi_down) { knx.loop(); } // Process knx events
if (!global_state.network_down) { knx.loop(); } // Process knx events
break;
case FUNC_EVERY_50_MSECOND:
if (toggle_inhibit) {

View File

@ -27,14 +27,14 @@ const char kHAssJsonSensorTypes[] PROGMEM =
D_JSON_APPARENT_POWERUSAGE "|Battery|" D_JSON_CURRENT "|" D_JSON_DISTANCE "|" D_JSON_FREQUENCY "|" D_JSON_HUMIDITY "|" D_JSON_ILLUMINANCE "|"
D_JSON_MOISTURE "|PB0.3|PB0.5|PB1|PB2.5|PB5|PB10|PM1|PM2.5|PM10|" D_JSON_POWERFACTOR "|" D_JSON_POWERUSAGE "|" D_JSON_TOTAL_START_TIME "|"
D_JSON_REACTIVE_POWERUSAGE "|" D_JSON_TODAY "|" D_JSON_TOTAL "|" D_JSON_VOLTAGE "|" D_JSON_WEIGHT "|" D_JSON_YESTERDAY "|"
D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|";
D_JSON_CO2 "|" D_JSON_ECO2 "|" D_JSON_TVOC "|" D_COLOR_RED "|" D_COLOR_GREEN "|" D_COLOR_BLUE"|" D_CCT "|" D_PROXIMITY "|Ambient|";
const char kHAssJsonSensorUnits[] PROGMEM =
"||||"
"VA|%|A|Cm|Hz|%|LX|"
"%|ppd|ppd|ppd|ppd|ppd|ppd|µg/m³|µg/m³|µg/m³|Cos φ|W| |"
"VAr|kWh|kWh|V|Kg|kWh|"
"ppm|ppm|ppb|";
"ppm|ppm|ppb|R|G|B|" D_UNIT_KELVIN "| |LX|";
const char kHAssJsonSensorDevCla[] PROGMEM =
"dev_cla\":\"temperature|ic\":\"mdi:weather-rainy|dev_cla\":\"pressure|dev_cla\":\"pressure|"
@ -42,19 +42,22 @@ const char kHAssJsonSensorDevCla[] PROGMEM =
"ic\":\"mdi:cup-water|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|ic\":\"mdi:flask|"
"ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:air-filter|ic\":\"mdi:alpha-f-circle-outline|dev_cla\":\"power|ic\":\"mdi:progress-clock|"
"dev_cla\":\"power|dev_cla\":\"power|dev_cla\":\"power|ic\":\"mdi:alpha-v-circle-outline|ic\":\"mdi:scale|dev_cla\":\"power|"
"ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|";
"ic\":\"mdi:periodic-table-co2|ic\":\"mdi:air-filter|ic\":\"mdi:periodic-table-co2|"
"ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:palette|ic\":\"mdi:temperature-kelvin|ic\":\"mdi:ruler|dev_cla\":\"illuminance|";
//"ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|ic\":\"mdi:weather-windy|"
// List of sensors ready for discovery
const char HASS_DISCOVER_BASE[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1
"\"stat_t\":\"%s\""; // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
const char HASS_DISCOVER_SENSOR[] PROGMEM =
",\"unit_of_meas\":\"%s\",\"%s\"," // unit of measure and class (or icon)
"\"frc_upd\":true," // force update for better graph representation
"\"val_tpl\":\"{{value_json['%s']['%s']"; // "COUNTER":{"C1":0} -> {{ value_json['COUNTER']['C1']
const char HASS_DISCOVER_BASE[] PROGMEM =
"{\"name\":\"%s\"," // dualr2 1
"\"stat_t\":\"%s\"," // stat/dualr2/RESULT (implies "\"optimistic\":\"false\",")
"\"avty_t\":\"%s\"," // tele/dualr2/LWT
const char HASS_DISCOVER_SENSOR_LWT[] PROGMEM =
",\"avty_t\":\"%s\"," // tele/dualr2/LWT
"\"pl_avail\":\"" D_ONLINE "\"," // Online
"\"pl_not_avail\":\"" D_OFFLINE "\""; // Offline
@ -141,7 +144,7 @@ const char kHAssTriggerStringButtons[] PROGMEM =
"|SINGLE|DOUBLE|TRIPLE|QUAD|PENTA|HOLD|";
const char kHAssError1[] PROGMEM =
"HASS: MQTT discovery failed due to too long topic or friendly name. Please shorten topic and/or friendly name. Failed to format";
"HASS: MQTT discovery failed due to too long topic or device/friendly name. Please shorten topic and/or device/friendly name. Failed to format";
const char kHAssError2[] PROGMEM =
"HASS: The configuration of the Relays is wrong, there is a Light that is using an index higher than the number of the validated relay.\n "
@ -195,13 +198,22 @@ void HAssAnnounceRelayLight(void)
bool ct_light = false; // Controls a CT Light when SetOption37 is >= 128
bool wt_light = false; // Controls a White Light when SetOption37 is >= 128
bool err_flag = false; // When true it blocks the creation of entities if the order of the Relays is not correct to avoid issue with Lights
bool TuyaMod = false; // Controls Tuya MCU modules
bool PwmMod = false; // Controls PWM_DIMMER module
bool FanMod = false; // Controls SONOFF_IFAN0X modules
uint8_t dimmer = 1;
uint8_t valid_relay = 0;
uint8_t max_lights = 1;
uint8_t TuyaRel = 0;
uint8_t TuyaRelInv = 0;
uint8_t TuyaDim = 0;
#ifdef ESP8266
if (PWM_DIMMER == my_module_type) { PwmMod = true; }
if (PWM_DIMMER == my_module_type ) { PwmMod = true; } //
if (SONOFF_IFAN02 == my_module_type || SONOFF_IFAN03 == my_module_type) { FanMod = true; }
if (SONOFF_DUAL == my_module_type) { valid_relay = 2; }
if (TUYA_DIMMER == my_module_type || SK03_TUYA == my_module_type) { TuyaMod = true; }
#endif //ESP8266
// If there is a special Light to be enabled and managed with SetOption68 or SetOption37 >= 128, Discovery calculates the maximum number of entities to be generated in advance
@ -209,17 +221,21 @@ void HAssAnnounceRelayLight(void)
if (PwmMulti) { max_lights = Light.subtype; }
if (!LightControl) {
ind_light = 1;
ind_light = true;
if (!PwmMulti) { max_lights = 2;}
}
// Lights types: 0 = LST_NONE / 1 = LST_SINGLE / 2 = LST_COLDWARM / 3 = LST_RGB / 4 = LST_RGBW / 5 = LST_RGBCW
for (uint32_t i = 1; i <= MAX_RELAYS; i++)
{
bool RelayX = PinUsed(GPIO_REL1 +i-1);
is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod; // SetOption30 - Enforce HAss autodiscovery as light
#ifdef USE_TUYA_MCU
TuyaRel = TuyaGetDpId((TUYA_MCU_FUNC_REL1+ i-1) + active_device - 1);
TuyaRelInv = TuyaGetDpId((TUYA_MCU_FUNC_REL1_INV+ i-1) + active_device - 1);
TuyaDim = TuyaGetDpId((TUYA_MCU_FUNC_DIMMER) + active_device - 1);
#endif //USE_TUYA_MCU
bool RelayX = PinUsed(GPIO_REL1 +i-1) || (valid_relay >= i) || (TuyaRel > 0 && TuyaMod) || (TuyaRelInv > 0 && TuyaMod); // Check if the gpio is configured as Relay or force it for Sonoff DUAL R1 with MCU and Tuya MCU
is_topic_light = Settings.flag.hass_light && RelayX || light_type && !RelayX || PwmMod || (TuyaDim > 0 && TuyaMod); // SetOption30 - Enforce HAss autodiscovery as light
mqtt_data[0] = '\0'; // Clear retained message
// Clear "other" topic first in case the device has been reconfigured from light to switch or vice versa
@ -255,13 +271,14 @@ void HAssAnnounceRelayLight(void)
GetTopic_P(command_topic, CMND, mqtt_topic, value_template);
GetTopic_P(state_topic, TELE, mqtt_topic, D_RSLT_STATE);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_RELAY, command_topic, value_template, SettingsText(SET_STATE_TXT1), SettingsText(SET_STATE_TXT2));
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
#ifdef USE_LIGHT
if (i >= Light.device) {
if (!RelayX || PwmMod) {
if (!RelayX || PwmMod || (TuyaDim > 0 && TuyaMod)) {
char *brightness_command_topic = stemp1;
strncpy_P(stemp3, Settings.flag.not_power_linked ? PSTR("last") : PSTR("brightness"), sizeof(stemp3)); // SetOption20 - Control power in relation to Dimmer/Color/Ct changes
char channel_num[9];
@ -411,6 +428,14 @@ void HAssAnnouncerBinSensors(uint8_t device, uint8_t present, uint8_t dual, uint
TryResponseAppend_P(HASS_DISCOVER_BIN_PIR, PSTR(D_RSLT_STATE), SettingsText(SET_STATE_TXT2));
}
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
#ifdef DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
#else
if (Settings.deepsleep == 0)
{
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
}
#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(PSTR("}"));
}
}
@ -505,7 +530,7 @@ void HAssAnnounceButtons(void)
{
button_present = 1;
} else
#endif
#endif // ESP8266
{
if (PinUsed(GPIO_KEY1, button_index)) {
button_present = 1;
@ -557,12 +582,21 @@ void HAssAnnounceSensor(const char *sensorname, const char *subsensortype, const
char prefix[TOPSZ];
char *state_topic = stemp1;
char *availability_topic = stemp2;
//bool LwtSensor = MQTT_LWT_DISCOVERY;
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_SENSOR));
snprintf_P(name, sizeof(name), PSTR("%s %s %s"), SettingsText(SET_DEVICENAME), sensorname, MultiSubName);
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
#ifdef DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
#else
if (Settings.deepsleep == 0)
{
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
}
#endif //DEEPSLEEP_LWT_HA_DISCOVERY
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId());
@ -629,8 +663,8 @@ void HAssAnnounceSensors(void)
sensordata[0] = '{';
snprintf_P(sensordata, sizeof(sensordata), PSTR("%s}"), sensordata); // {"INA219":{"Voltage":4.494,"Current":0.020,"Power":0.089}}
// USE THE FOLLOWING LINE TO TEST JSON
//snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"HX711\":{\"Weight\":[22,34,1023.4]}}"));
//snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"APDS9960\":{\"Red\":282,\"Green\":252,\"Blue\":196,\"Ambient\":169,\"CCT\":4217,\"Proximity\":9}}"));
//snprintf_P(sensordata, sizeof(sensordata), PSTR("{\"ENERGY\":{\"TotalStartTime\":\"2018-11-23T15:33:47\",\"Total\":0.017,\"TotalTariff\":[0.000,0.017],\"Yesterday\":0.000,\"Today\":0.002,\"ExportActive\":0.000,\"ExportTariff\":[0.000,0.000],\"Period\":0.00,\"Power\":0.00,\"ApparentPower\":7.84,\"ReactivePower\":-7.21,\"Factor\":0.39,\"Frequency\":50.0,\"Voltage\":234.31,\"Current\":0.039,\"ImportActive\":12.580,\"ImportReactive\":0.002,\"ExportReactive\":39.131,\"PhaseAngle\":290.45}}"));
StaticJsonBuffer<500> jsonBuffer;
JsonObject &root = jsonBuffer.parseObject(sensordata);
@ -703,7 +737,8 @@ void HAssAnnounceDeviceInfoAndStatusSensor(void)
GetTopic_P(state_topic, TELE, mqtt_topic, PSTR(D_RSLT_HASS_STATE));
GetTopic_P(availability_topic, TELE, mqtt_topic, S_LWT);
Response_P(HASS_DISCOVER_BASE, name, state_topic, availability_topic);
Response_P(HASS_DISCOVER_BASE, name, state_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, availability_topic);
TryResponseAppend_P(HASS_DISCOVER_SENSOR_HASS_STATUS, state_topic);
TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO, unique_id, ESP_getChipId(), SettingsText(SET_DEVICENAME),
ModuleName().c_str(), my_version, my_image);
@ -812,7 +847,6 @@ void HAssAnyKey(void)
bool Xdrv12(uint8_t function)
{
bool result = false;
if (Settings.flag.mqtt_enabled)
{ // SetOption3 - Enable MQTT
switch (function)
@ -844,6 +878,9 @@ bool Xdrv12(uint8_t function)
case FUNC_MQTT_INIT:
hass_mode = 0; // Discovery only if Settings.flag.hass_discovery is set
hass_init_step = 2; // Delayed discovery
// if (!Settings.flag.hass_discovery) {
// AddLog_P2(LOG_LEVEL_INFO, PSTR("MQT: homeassistant/49A3BC/Discovery = {\"dev\":{\"ids\":[\"49A3BC\"]},\"cmd_t\":\"cmnd/test1/\",\"Discovery\":0}"));
// }
break;
}
}

View File

@ -1013,14 +1013,14 @@ void DisplayLogBufferInit(void)
snprintf_P(buffer, sizeof(buffer), PSTR("Display mode %d"), Settings.display_mode);
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), my_hostname);
snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), NetworkHostname());
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active));
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), NetworkMacAddress().c_str());
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), WiFi.macAddress().c_str());
snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), NetworkAddress().toString().c_str());
DisplayLogBufferAdd(buffer);
if (!global_state.wifi_down) {
snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), WiFi.localIP().toString().c_str());
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active));
DisplayLogBufferAdd(buffer);
snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_RSSI " %d%%"), WifiGetRssiAsQuality(WiFi.RSSI()));
DisplayLogBufferAdd(buffer);

View File

@ -19,6 +19,13 @@
#ifdef USE_ZIGBEE
#if defined(USE_ZIGBEE_ZNP) && defined(USE_ZIGBEE_EZSP)
#error "#define USE_ZIGBEE_ZNP and #define USE_ZIGBEE_EZSP are mutually incompatible"
#endif
#if !defined(USE_ZIGBEE_ZNP) && !defined(USE_ZIGBEE_EZSP)
#error "You must select one of: #define USE_ZIGBEE_ZNP or #define USE_ZIGBEE_EZSP"
#endif
#define OCCUPANCY "Occupancy" // global define for Aqara
typedef uint64_t Z_IEEEAddress;
@ -26,6 +33,7 @@ typedef uint16_t Z_ShortAddress;
const uint16_t BAD_SHORTADDR = 0xFFFE;
#ifdef USE_ZIGBEE_ZNP
enum ZnpCommandType {
Z_POLL = 0x00,
Z_SREQ = 0x20,
@ -45,6 +53,7 @@ enum ZnpSubsystem {
Z_DEBUG = 0x08,
Z_APP = 0x09
};
#endif // USE_ZIGBEE_ZNP
// Commands in the SYS subsystem
enum SysCommand {

View File

@ -168,6 +168,8 @@ SBuffer *zigbee_buffer = nullptr;
#define USE_ZIGBEE_CHANNEL_MASK (1 << (USE_ZIGBEE_CHANNEL))
#ifdef USE_ZIGBEE_ZNP
// ZBS_* Zigbee Send
// ZBR_* Zigbee Recv
ZBM(ZBS_RESET, Z_AREQ | Z_SYS, SYS_RESET, 0x00 ) // 410001 SYS_RESET_REQ Hardware reset
@ -611,6 +613,30 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_STOP(ZIGBEE_LABEL_ABORT)
};
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
// Update the relevant commands with Settings
void Z_UpdateConfig(uint8_t zb_channel, uint16_t zb_pan_id, uint64_t zb_ext_panid, uint64_t zb_precfgkey_l, uint64_t zb_precfgkey_h) {
}
static const Zigbee_Instruction zb_prog[] PROGMEM = {
ZI_LABEL(0)
ZI_NOOP()
ZI_ON_ERROR_GOTO(ZIGBEE_LABEL_ABORT)
ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT)
// ZI_ON_RECV_UNEXPECTED(&Z_Recv_Default)
// ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize
ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP)
ZI_WAIT_FOREVER()
ZI_GOTO(ZIGBEE_LABEL_READY)
};
#endif // USE_ZIGBEE_EZSP
uint8_t ZigbeeGetInstructionSize(uint8_t instr) { // in Zigbee_Instruction lines (words)
if (instr >= ZGB_INSTR_12_BYTES) {
return 3;
@ -770,7 +796,9 @@ void ZigbeeStateMachine_Run(void) {
}
break;
case ZGB_INSTR_SEND:
#ifdef USE_ZIGBEE_ZNP
ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */);
#endif // USE_ZIGBEE_ZNP
break;
case ZGB_INSTR_WAIT_UNTIL:
zigbee.recv_until = true; // and reuse ZGB_INSTR_WAIT_RECV

View File

@ -552,6 +552,7 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) {
return -1;
}
#ifdef USE_ZIGBEE_ZNP
/*********************************************************************************************\
* Send specific ZNP messages
\*********************************************************************************************/
@ -589,6 +590,32 @@ void Z_SendAFInfoRequest(uint16_t shortaddr) {
ZigbeeZNPSend(AFInfoReq, sizeof(AFInfoReq));
}
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Send specific EZS¨ messages
\*********************************************************************************************/
//
// Send ZDO_IEEE_ADDR_REQ request to get IEEE long address
//
void Z_SendIEEEAddrReq(uint16_t shortaddr) {
}
//
// Send ACTIVE_EP_REQ to collect active endpoints for this address
//
void Z_SendActiveEpReq(uint16_t shortaddr) {
}
//
// Send AF Info Request
//
void Z_SendAFInfoRequest(uint16_t shortaddr) {
}
#endif // USE_ZIGBEE_EZSP
/*********************************************************************************************\
* Callbacks
@ -718,6 +745,8 @@ typedef struct Z_Dispatcher {
ZB_RecvMsgFunc func;
} Z_Dispatcher;
#ifdef USE_ZIGBEE_ZNP
// Ffilters based on ZNP frames
ZBM(AREQ_AF_DATA_CONFIRM, Z_AREQ | Z_AF, AF_DATA_CONFIRM) // 4480
ZBM(AREQ_AF_INCOMING_MESSAGE, Z_AREQ | Z_AF, AF_INCOMING_MSG) // 4481
@ -767,6 +796,8 @@ int32_t Z_Recv_Default(int32_t res, const class SBuffer &buf) {
}
}
#endif // USE_ZIGBEE_ZNP
/*********************************************************************************************\
* Functions called by State Machine
\*********************************************************************************************/
@ -835,8 +866,8 @@ void Z_AutoResponder(uint16_t srcaddr, uint16_t cluster, uint8_t endpoint, const
// responder
switch (cluster) {
case 0x0000:
if (HasKeyCaseInsensitive(json, PSTR("ModelId"))) { json_out[F("ModelId")] = F("Tasmota Z2T"); }
if (HasKeyCaseInsensitive(json, PSTR("Manufacturer"))) { json_out[F("Manufacturer")] = F("Tasmota"); }
if (HasKeyCaseInsensitive(json, PSTR("ModelId"))) { json_out[F("ModelId")] = F(USE_ZIGBEE_MODELID); }
if (HasKeyCaseInsensitive(json, PSTR("Manufacturer"))) { json_out[F("Manufacturer")] = F(USE_ZIGBEE_MANUFACTURER); }
break;
#ifdef USE_LIGHT
case 0x0006:

View File

@ -21,18 +21,32 @@
#define XDRV_23 23
#ifdef USE_ZIGBEE_ZNP
const uint32_t ZIGBEE_BUFFER_SIZE = 256; // Max ZNP frame is SOF+LEN+CMD1+CMD2+250+FCS = 255
const uint8_t ZIGBEE_SOF = 0xFE;
const uint8_t ZIGBEE_SOF_ALT = 0xFF;
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
const uint32_t ZIGBEE_BUFFER_SIZE = 256;
const uint8_t ZIGBEE_EZSP_CANCEL = 0x1A; // cancel byte
const uint8_t ZIGBEE_EZSP_EOF = 0x7E; // end of frame
const uint8_t ZIGBEE_EZSP_ESCAPE = 0x7D; // escape byte
#endif // USE_ZIGBEE_EZSP
#include <TasmotaSerial.h>
TasmotaSerial *ZigbeeSerial = nullptr;
const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEE_PERMITJOIN "|"
D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|"
D_CMND_ZIGBEE_PROBE "|" D_CMND_ZIGBEEZNPRECEIVE "|"
#ifdef USE_ZIGBEE_ZNP
D_CMND_ZIGBEEZNPSEND "|" D_CMND_ZIGBEEZNPRECEIVE "|"
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
D_CMND_ZIGBEE_EZSP_SEND "|" D_CMND_ZIGBEE_EZSP_RECEIVE "|"
#endif // USE_ZIGBEE_EZSP
D_CMND_ZIGBEE_PERMITJOIN "|"
D_CMND_ZIGBEE_STATUS "|" D_CMND_ZIGBEE_RESET "|" D_CMND_ZIGBEE_SEND "|" D_CMND_ZIGBEE_PROBE "|"
D_CMND_ZIGBEE_FORGET "|" D_CMND_ZIGBEE_SAVE "|" D_CMND_ZIGBEE_NAME "|"
D_CMND_ZIGBEE_BIND "|" D_CMND_ZIGBEE_UNBIND "|" D_CMND_ZIGBEE_PING "|" D_CMND_ZIGBEE_MODELID "|"
D_CMND_ZIGBEE_LIGHT "|" D_CMND_ZIGBEE_RESTORE "|" D_CMND_ZIGBEE_BIND_STATE "|"
@ -40,9 +54,14 @@ const char kZbCommands[] PROGMEM = D_PRFX_ZB "|" // prefix
;
void (* const ZigbeeCommand[])(void) PROGMEM = {
&CmndZbZNPSend, &CmndZbPermitJoin,
&CmndZbStatus, &CmndZbReset, &CmndZbSend,
&CmndZbProbe, &CmndZbZNPReceive,
#ifdef USE_ZIGBEE_ZNP
&CmndZbZNPSend, &CmndZbZNPReceive,
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
&CmndZbEZSPSend, &CmndZbEZSPReceive,
#endif // USE_ZIGBEE_EZSP
&CmndZbPermitJoin,
&CmndZbStatus, &CmndZbReset, &CmndZbSend, &CmndZbProbe,
&CmndZbForget, &CmndZbSave, &CmndZbName,
&CmndZbBind, &CmndZbUnbind, &CmndZbPing, &CmndZbModelId,
&CmndZbLight, &CmndZbRestore, &CmndZbBindState,
@ -52,11 +71,12 @@ void (* const ZigbeeCommand[])(void) PROGMEM = {
//
// Called at event loop, checks for incoming data from the CC2530
//
void ZigbeeInputLoop(void)
{
static uint32_t zigbee_polling_window = 0;
void ZigbeeInputLoop(void) {
#ifdef USE_ZIGBEE_ZNP
static uint32_t zigbee_polling_window = 0; // number of milliseconds since first byte
static uint8_t fcs = ZIGBEE_SOF;
static uint32_t zigbee_frame_len = 5; // minimal zigbee frame lenght, will be updated when buf[1] is read
static uint32_t zigbee_frame_len = 5; // minimal zigbee frame length, will be updated when buf[1] is read
// Receive only valid ZNP frames:
// 00 - SOF = 0xFE
// 01 - Length of Data Field - 0..250
@ -140,6 +160,127 @@ void ZigbeeInputLoop(void)
}
zigbee_buffer->setLen(0); // empty buffer
}
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
static uint32_t zigbee_polling_window = 0; // number of milliseconds since first byte
bool escape = false; // was the previous byte an escape?
bool frame_complete = false; // frame is ready and complete
// Receive only valid EZSP frames:
// 1A - Cancel - cancel all previous bytes
// 7D - Escape byte - following byte is escaped
// 7E - end of frame
while (ZigbeeSerial->available()) {
yield();
uint8_t zigbee_in_byte = ZigbeeSerial->read();
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x%02X len=%d"), zigbee_in_byte, zigbee_buffer->len());
// if (0 == zigbee_buffer->len()) { // make sure all variables are correctly initialized
// escape = false;
// frame_complete = false;
// }
if ((0x11 == zigbee_in_byte) || (0x13 == zigbee_in_byte)) {
continue; // ignore reserved bytes XON/XOFF
}
if (ZIGBEE_EZSP_ESCAPE == zigbee_in_byte) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Escape byte received"));
escape = true;
continue;
}
if (ZIGBEE_EZSP_CANCEL == zigbee_in_byte) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x1A, cancel byte received, discarding %d bytes"), zigbee_buffer->len());
zigbee_buffer->setLen(0); // empty buffer
escape = false;
frame_complete = false;
continue; // re-loop
}
if (ZIGBEE_EZSP_EOF == zigbee_in_byte) {
// end of frame
frame_complete = true;
break;
}
if (zigbee_buffer->len() < ZIGBEE_BUFFER_SIZE) {
if (escape) {
// invert bit 5
zigbee_in_byte ^= 0x20;
escape = false;
}
zigbee_buffer->add8(zigbee_in_byte);
zigbee_polling_window = millis(); // Wait for more data
} // adding bytes
} // while (ZigbeeSerial->available())
uint32_t frame_len = zigbee_buffer->len();
if (frame_complete || (frame_len && (millis() > (zigbee_polling_window + ZIGBEE_POLLING)))) {
char hex_char[frame_len * 2 + 2];
ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char));
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric());
if ((frame_complete) && (frame_len >= 3)) {
// frame received and has at least 3 bytes (without EOF), checking CRC
// AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": received raw frame %s"), hex_char);
uint16_t crc = 0xFFFF; // frame CRC
// compute CRC
for (uint32_t i=0; i<frame_len-2; i++) {
crc = crc ^ ((uint16_t)zigbee_buffer->get8(i) << 8);
for (uint32_t i=0; i<8; i++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021; // polynom is x^16 + x^12 + x^5 + 1, CCITT standard
} else {
crc <<= 1;
}
}
}
uint16_t crc_received = zigbee_buffer->get8(frame_len - 2) << 8 | zigbee_buffer->get8(frame_len - 1);
// remove 2 last bytes
if (crc_received != crc) {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": bad crc (received 0x%04X, computed 0x%04X) %s"), crc_received, crc, hex_char);
} else {
// copy buffer
SBuffer ezsp_buffer = zigbee_buffer->subBuffer(0, frame_len - 2); // CRC
// CRC is correct, apply de-stuffing if DATA frame
if (0 == (ezsp_buffer.get8(0) & 0x80)) {
// DATA frame
uint8_t rand = 0x42;
for (uint32_t i=1; i<ezsp_buffer.len(); i++) {
ezsp_buffer.set8(i, ezsp_buffer.get8(i) ^ rand);
if (rand & 1) { rand = (rand >> 1) ^ 0xB8; }
else { rand = (rand >> 1); }
}
}
ToHex_P((unsigned char*)ezsp_buffer.getBuffer(), ezsp_buffer.len(), hex_char, sizeof(hex_char));
Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "\":\"%s\"}"), hex_char);
if (Settings.flag3.tuya_serial_mqtt_publish) {
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR));
XdrvRulesProcess();
} else {
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable
}
// now process the message
ZigbeeProcessInput(ezsp_buffer);
}
} else {
// the buffer timed-out, print error and discard
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": time-out, discarding %s, %d"), hex_char);
}
zigbee_buffer->setLen(0); // empty buffer
escape = false;
frame_complete = false;
}
#endif // USE_ZIGBEE_EZSP
}
/********************************************************************************************/
@ -201,15 +342,20 @@ uint32_t strToUInt(const JsonVariant &val) {
return 0; // couldn't parse anything
}
#ifdef USE_ZIGBEE_ZNP
// Do a factory reset of the CC2530
const unsigned char ZIGBEE_FACTORY_RESET[] PROGMEM =
{ Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x01 /* STARTOPT_CLEAR_CONFIG */};
//"2605030101"; // Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 len, 0x01 STARTOPT_CLEAR_CONFIG
#endif // USE_ZIGBEE_ZNP
void CmndZbReset(void) {
if (ZigbeeSerial) {
switch (XdrvMailbox.payload) {
case 1:
#ifdef USE_ZIGBEE_ZNP
ZigbeeZNPSend(ZIGBEE_FACTORY_RESET, sizeof(ZIGBEE_FACTORY_RESET));
#endif // USE_ZIGBEE_ZNP
eraseZigbeeDevices();
restart_flag = 2;
ResponseCmndChar_P(PSTR(D_JSON_ZIGBEE_CC2530 " " D_JSON_RESET_AND_RESTARTING));
@ -220,6 +366,38 @@ void CmndZbReset(void) {
}
}
#ifdef USE_ZIGBEE_ZNP
void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
if ((len < 2) || (len > 252)) {
// abort, message cannot be less than 2 bytes for CMD1 and CMD2
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEEZNPSENT ": bad message len %d"), len);
return;
}
uint8_t data_len = len - 2; // removing CMD1 and CMD2
if (ZigbeeSerial) {
uint8_t fcs = data_len;
ZigbeeSerial->write(ZIGBEE_SOF); // 0xFE
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF);
ZigbeeSerial->write(data_len);
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len);
for (uint32_t i = 0; i < len; i++) {
uint8_t b = pgm_read_byte(msg + i);
ZigbeeSerial->write(b);
fcs ^= b;
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b);
}
ZigbeeSerial->write(fcs); // finally send fcs checksum byte
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs);
}
// Now send a MQTT message to report the sent message
char hex_char[(len * 2) + 2];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"),
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
}
//
// Same code for `ZbZNPSend` and `ZbZNPReceive`
// building the complete message (intro, length)
@ -264,36 +442,138 @@ void CmndZbZNPSend(void)
CmndZbZNPSendOrReceive(true);
}
void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
if ((len < 2) || (len > 252)) {
#endif // USE_ZIGBEE_ZNP
#ifdef USE_ZIGBEE_EZSP
// internal function to output a byte, and escape it (stuffing) if needed
void ZigbeeEZSPSend_Out(uint8_t out_byte) {
switch (out_byte) {
case 0x7E: // Flag byte
case 0x11: // XON
case 0x13: // XOFF
case 0x18: // Substitute byte
case 0x1A: // Cancel byte
case 0x7D: // Escape byte
ZigbeeSerial->write(ZIGBEE_EZSP_ESCAPE); // send Escape byte 0x7D
ZigbeeSerial->write(out_byte ^ 0x20); // send with bit 5 inverted
break;
default:
ZigbeeSerial->write(out_byte); // send unchanged
break;
}
}
// Send low-level EZSP frames
//
// The frame should contain the Control Byte and Data Field
// The frame shouldn't be escaped, nor randomized
//
// Before sending:
// - send Cancel byte (0x1A) if requested
// - randomize Data Field if DATA Frame
// - compute CRC16
// - escape (stuff) reserved bytes
// - add EOF (0x7E)
// - send frame
// send_cancel: should we first send a EZSP_CANCEL (0x1A) before the message to clear any leftover
void ZigbeeEZSPSend(const uint8_t *msg, size_t len, bool send_cancel = false) {
if ((len < 1) || (len > 252)) {
// abort, message cannot be less than 2 bytes for CMD1 and CMD2
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEEZNPSENT ": bad message len %d"), len);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_JSON_ZIGBEE_EZSP_SENT ": bad message len %d"), len);
return;
}
uint8_t data_len = len - 2; // removing CMD1 and CMD2
if (ZigbeeSerial) {
uint8_t fcs = data_len;
ZigbeeSerial->write(ZIGBEE_SOF); // 0xFE
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend SOF %02X"), ZIGBEE_SOF);
ZigbeeSerial->write(data_len);
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend LEN %02X"), data_len);
for (uint32_t i = 0; i < len; i++) {
uint8_t b = pgm_read_byte(msg + i);
ZigbeeSerial->write(b);
fcs ^= b;
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend byt %02X"), b);
if (send_cancel) {
ZigbeeSerial->write(ZIGBEE_EZSP_CANCEL); // 0x1A
}
ZigbeeSerial->write(fcs); // finally send fcs checksum byte
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZNPSend FCS %02X"), fcs);
bool data_frame = (0 == (msg[0] & 0x80));
uint8_t rand = 0x42; // pseudo-randomizer initial value
uint16_t crc = 0xFFFF; // CRC16 CCITT initialization
for (uint32_t i=0; i<len; i++) {
uint8_t out_byte = msg[i];
// apply randomization if DATA field
if (data_frame && (i > 0)) {
out_byte ^= rand;
if (rand & 1) { rand = (rand >> 1) ^ 0xB8; }
else { rand = (rand >> 1); }
}
// compute CRC
crc = crc ^ ((uint16_t)out_byte << 8);
for (uint32_t i=0; i<8; i++) {
if (crc & 0x8000) {
crc = (crc << 1) ^ 0x1021; // polynom is x^16 + x^12 + x^5 + 1, CCITT standard
} else {
crc <<= 1;
}
}
// output byte
ZigbeeEZSPSend_Out(out_byte);
}
// send CRC16 in big-endian
ZigbeeEZSPSend_Out(crc >> 8);
ZigbeeEZSPSend_Out(crc & 0xFF);
// finally send End of Frame
ZigbeeSerial->write(ZIGBEE_EZSP_EOF); // 0x1A
}
// Now send a MQTT message to report the sent message
char hex_char[(len * 2) + 2];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " %s"),
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT " %s"),
ToHex_P(msg, len, hex_char, sizeof(hex_char)));
}
//
// Same code for `ZbZNPSend` and `ZbZNPReceive`
// building the complete message (intro, length)
//
void CmndZbEZSPSendOrReceive(bool send)
{
if (ZigbeeSerial && (XdrvMailbox.data_len > 0)) {
uint8_t code;
char *codes = RemoveSpace(XdrvMailbox.data);
int32_t size = strlen(XdrvMailbox.data);
SBuffer buf((size+1)/2);
while (size > 1) {
char stemp[3];
strlcpy(stemp, codes, sizeof(stemp));
code = strtol(stemp, nullptr, 16);
buf.add8(code);
size -= 2;
codes += 2;
}
if (send) {
// Command was `ZbEZSPSend`
ZigbeeEZSPSend(buf.getBuffer(), buf.len());
} else {
// Command was `ZbEZSPReceive`
ZigbeeProcessInput(buf);
}
}
ResponseCmndDone();
}
// For debug purposes only, simulates a message received
void CmndZbEZSPReceive(void)
{
CmndZbEZSPSendOrReceive(false);
}
void CmndZbEZSPSend(void)
{
CmndZbEZSPSendOrReceive(true);
}
#endif // USE_ZIGBEE_EZSP
//
// Internal function, send the low-level frame
// Input:
@ -311,6 +591,7 @@ void ZigbeeZNPSend(const uint8_t *msg, size_t len) {
//
void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterId, uint8_t endpoint, uint8_t cmdId, bool clusterSpecific, uint16_t manuf, const uint8_t *msg, size_t len, bool needResponse, uint8_t transacId) {
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(32+len);
buf.add8(Z_SREQ | Z_AF); // 24
buf.add8(AF_DATA_REQUEST_EXT); // 02
@ -342,6 +623,7 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI
}
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
}
/********************************************************************************************/
@ -914,6 +1196,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
if (&to_group && dstLongAddr) { ResponseCmndChar_P(PSTR("Cannot have both \"ToDevice\" and \"ToGroup\"")); return; }
if (!&to_group && !dstLongAddr) { ResponseCmndChar_P(PSTR("Missing \"ToDevice\" or \"ToGroup\"")); return; }
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO);
if (unbind) {
@ -935,6 +1218,7 @@ void ZbBindUnbind(bool unbind) { // false = bind, true = unbind
}
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}
@ -961,6 +1245,7 @@ void CmndZbBindState(void) {
uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data);
if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; }
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(10);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_BIND_REQ); // 33
@ -968,6 +1253,7 @@ void CmndZbBindState(void) {
buf.add8(0); // StartIndex = 0
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}
@ -1191,6 +1477,7 @@ void CmndZbPermitJoin(void) {
duration = 0xFF; // unlimited time
}
#ifdef USE_ZIGBEE_ZNP
SBuffer buf(34);
buf.add8(Z_SREQ | Z_ZDO); // 25
buf.add8(ZDO_MGMT_PERMIT_JOIN_REQ); // 36
@ -1200,6 +1487,7 @@ void CmndZbPermitJoin(void) {
buf.add8(0x00); // TCSignificance
ZigbeeZNPSend(buf.getBuffer(), buf.len());
#endif // USE_ZIGBEE_ZNP
ResponseCmndDone();
}

View File

@ -0,0 +1,585 @@
/*
xdrv_31_tasmota_client.ino - Support for external microcontroller on serial
Copyright (C) 2020 Andre Thomas and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_TASMOTA_CLIENT
/*********************************************************************************************\
* Tasmota to microcontroller
\*********************************************************************************************/
#define XDRV_31 31
#define CONST_STK_CRC_EOP 0x20
#define CMND_STK_GET_SYNC 0x30
#define CMND_STK_SET_DEVICE 0x42
#define CMND_STK_SET_DEVICE_EXT 0x45
#define CMND_STK_ENTER_PROGMODE 0x50
#define CMND_STK_LEAVE_PROGMODE 0x51
#define CMND_STK_LOAD_ADDRESS 0x55
#define CMND_STK_PROG_PAGE 0x64
/*************************************************\
* Tasmota Client Specific Commands
\*************************************************/
#define CMND_START 0xFC
#define CMND_END 0xFD
#define CMND_FEATURES 0x01
#define CMND_JSON 0x02
#define CMND_FUNC_EVERY_SECOND 0x03
#define CMND_FUNC_EVERY_100_MSECOND 0x04
#define CMND_CLIENT_SEND 0x05
#define CMND_PUBLISH_TELE 0x06
#define CMND_EXECUTE_CMND 0x07
#define PARAM_DATA_START 0xFE
#define PARAM_DATA_END 0xFF
#include <TasmotaSerial.h>
/*
* Embedding class in here since its rather specific to Arduino bootloader
*/
class SimpleHexParse {
public:
SimpleHexParse(void);
uint8_t parseLine(char *hexline);
uint8_t ptr_l = 0;
uint8_t ptr_h = 0;
bool PageIsReady = false;
bool firstrun = true;
bool EndOfFile = false;
uint8_t FlashPage[128];
uint8_t FlashPageIdx = 0;
uint8_t layoverBuffer[16];
uint8_t layoverIdx = 0;
uint8_t getByte(char *hexline, uint8_t idx);
};
SimpleHexParse::SimpleHexParse(void) {
}
uint8_t SimpleHexParse::parseLine(char *hexline) {
if (layoverIdx) {
memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
FlashPageIdx = layoverIdx;
layoverIdx = 0;
}
uint8_t len = getByte(hexline, 1);
uint8_t addr_h = getByte(hexline, 2);
uint8_t addr_l = getByte(hexline, 3);
uint8_t rectype = getByte(hexline, 4);
for (uint8_t idx = 0; idx < len; idx++) {
if (FlashPageIdx < 128) {
FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
FlashPageIdx++;
} else { // We have layover bytes
layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
layoverIdx++;
}
}
if (1 == rectype) {
EndOfFile = true;
while (FlashPageIdx < 128) {
FlashPage[FlashPageIdx] = 0xFF;
FlashPageIdx++;
}
}
if (FlashPageIdx == 128) {
if (firstrun) {
firstrun = false;
} else {
ptr_l += 0x40;
if (ptr_l == 0) {
ptr_l = 0;
ptr_h++;
}
}
firstrun = false;
PageIsReady = true;
}
return 0;
}
uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx) {
char buff[3];
buff[3] = '\0';
memcpy(&buff, &hexline[(idx*2)-1], 2);
return strtol(buff, 0, 16);
}
/*
* End of embedded class SimpleHexParse
*/
struct TCLIENT {
uint32_t spi_hex_size = 0;
uint32_t spi_sector_counter = 0;
uint8_t spi_sector_cursor = 0;
uint8_t inverted = LOW;
bool type = false;
bool flashing = false;
bool SerialEnabled = false;
uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
bool unsupported = false;
} TClient;
typedef union {
uint32_t data;
struct {
uint32_t func_json_append : 1; // Client supports providing a JSON for TELEPERIOD
uint32_t func_every_second : 1; // Client supports receiving a FUNC_EVERY_SECOND callback with no response
uint32_t func_every_100_msecond : 1; // Client supports receiving a FUNC_EVERY_100_MSECOND callback with no response
uint32_t func_client_send : 1; // Client supports receiving commands with "client send xxx"
uint32_t spare4 : 1;
uint32_t spare5 : 1;
uint32_t spare6 : 1;
uint32_t spare7 : 1;
uint32_t spare8 : 1;
uint32_t spare9 : 1;
uint32_t spare10 : 1;
uint32_t spare11 : 1;
uint32_t spare12 : 1;
uint32_t spare13 : 1;
uint32_t spare14 : 1;
uint32_t spare15 : 1;
uint32_t spare16 : 1;
uint32_t spare17 : 1;
uint32_t spare18 : 1;
uint32_t spare19 : 1;
uint32_t spare20 : 1;
uint32_t spare21 : 1;
uint32_t spare22 : 1;
uint32_t spare23 : 1;
uint32_t spare24 : 1;
uint32_t spare25 : 1;
uint32_t spare26 : 1;
uint32_t spare27 : 1;
uint32_t spare28 : 1;
uint32_t spare29 : 1;
uint32_t spare30 : 1;
uint32_t spare31 : 1;
};
} TClientFeatureCfg;
/*
* The structure below must remain 4 byte aligned to be compatible with
* Tasmota as master
*/
struct TCLIENT_FEATURES {
uint32_t features_version;
TClientFeatureCfg features;
} TClientSettings;
struct TCLIENT_COMMAND {
uint8_t command;
uint8_t parameter;
uint8_t unused2;
uint8_t unused3;
} TClientCommand;
TasmotaSerial *TasmotaClient_Serial;
uint32_t TasmotaClient_FlashStart(void) {
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
}
uint8_t TasmotaClient_UpdateInit(void) {
TClient.spi_hex_size = 0;
TClient.spi_sector_counter = TasmotaClient_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
TClient.spi_sector_cursor = 0;
return 0;
}
void TasmotaClient_Reset(void) {
if (TClient.SerialEnabled) {
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
delay(1);
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), TClient.inverted);
delay(1);
digitalWrite(Pin(GPIO_TASMOTACLIENT_RST), !TClient.inverted);
delay(5);
}
}
uint8_t TasmotaClient_waitForSerialData(int dataCount, int timeout) {
int timer = 0;
while (timer < timeout) {
if (TasmotaClient_Serial->available() >= dataCount) {
return 1;
}
delay(1);
timer++;
}
return 0;
}
uint8_t TasmotaClient_sendBytes(uint8_t* bytes, int count) {
TasmotaClient_Serial->write(bytes, count);
TasmotaClient_waitForSerialData(2, 250);
uint8_t sync = TasmotaClient_Serial->read();
uint8_t ok = TasmotaClient_Serial->read();
if ((sync == 0x14) && (ok == 0x10)) {
return 1;
}
return 0;
}
uint8_t TasmotaClient_execCmd(uint8_t cmd) {
uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
return TasmotaClient_sendBytes(bytes, 2);
}
uint8_t TasmotaClient_execParam(uint8_t cmd, uint8_t* params, int count) {
uint8_t bytes[32];
bytes[0] = cmd;
int i = 0;
while (i < count) {
bytes[i + 1] = params[i];
i++;
}
bytes[i + 1] = CONST_STK_CRC_EOP;
return TasmotaClient_sendBytes(bytes, i + 2);
}
uint8_t TasmotaClient_exitProgMode(void) {
return TasmotaClient_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
}
uint8_t TasmotaClient_SetupFlash(void) {
uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_FLASH_SPEED);
if (TasmotaClient_Serial->hardwareSerial()) {
ClaimSerial();
}
TasmotaClient_Reset();
uint8_t timeout = 0;
uint8_t no_error = 0;
while (50 > timeout) {
if (TasmotaClient_execCmd(CMND_STK_GET_SYNC)) {
timeout = 200;
no_error = 1;
}
timeout++;
delay(1);
}
if (no_error) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Found bootloader"));
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Bootloader could not be found"));
}
if (no_error) {
if (TasmotaClient_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (1)"));
}
}
if (no_error) {
if (TasmotaClient_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Could not configure device for programming (2)"));
}
}
if (no_error) {
if (TasmotaClient_execCmd(CMND_STK_ENTER_PROGMODE)) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Failed to put bootloader into programming mode"));
}
}
return no_error;
}
uint8_t TasmotaClient_loadAddress(uint8_t adrHi, uint8_t adrLo) {
uint8_t params[] = { adrLo, adrHi };
return TasmotaClient_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
}
void TasmotaClient_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data) {
uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
TasmotaClient_loadAddress(addr_h, addr_l);
TasmotaClient_Serial->write(Header, 4);
for (int i = 0; i < 128; i++) {
TasmotaClient_Serial->write(data[i]);
}
TasmotaClient_Serial->write(CONST_STK_CRC_EOP);
TasmotaClient_waitForSerialData(2, 250);
TasmotaClient_Serial->read();
TasmotaClient_Serial->read();
}
void TasmotaClient_Flash(void) {
bool reading = true;
uint32_t read = 0;
uint32_t processed = 0;
char thishexline[50];
uint8_t position = 0;
char* flash_buffer;
SimpleHexParse hexParse = SimpleHexParse();
if (!TasmotaClient_SetupFlash()) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flashing aborted!"));
TClient.flashing = false;
restart_flag = 2;
return;
}
flash_buffer = new char[SPI_FLASH_SEC_SIZE];
uint32_t flash_start = TasmotaClient_FlashStart() * SPI_FLASH_SEC_SIZE;
while (reading) {
ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
read = read + SPI_FLASH_SEC_SIZE;
if (read >= TClient.spi_hex_size) {
reading = false;
}
for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
processed++;
if ((processed <= TClient.spi_hex_size) && (!hexParse.EndOfFile)) {
if (':' == flash_buffer[ca]) {
position = 0;
}
if (0x0D == flash_buffer[ca]) {
thishexline[position] = 0;
hexParse.parseLine(thishexline);
if (hexParse.PageIsReady) {
TasmotaClient_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
hexParse.PageIsReady = false;
hexParse.FlashPageIdx = 0;
}
} else {
if (0x0A != flash_buffer[ca]) {
thishexline[position] = flash_buffer[ca];
position++;
}
}
}
}
}
TasmotaClient_exitProgMode();
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Flash done!"));
TClient.flashing = false;
restart_flag = 2;
}
void TasmotaClient_SetFlagFlashing(bool value) {
TClient.flashing = value;
}
bool TasmotaClient_GetFlagFlashing(void) {
return TClient.flashing;
}
void TasmotaClient_WriteBuffer(uint8_t *buf, size_t size) {
if (0 == TClient.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
ESP.flashEraseSector(TClient.spi_sector_counter);
}
TClient.spi_sector_cursor++;
ESP.flashWrite((TClient.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TClient.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
TClient.spi_hex_size = TClient.spi_hex_size + size;
if (2 == TClient.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
TClient.spi_sector_cursor = 0;
TClient.spi_sector_counter++;
}
}
void TasmotaClient_Init(void) {
if (TClient.type) {
return;
}
if (10 > TClient.waitstate) {
TClient.waitstate++;
return;
}
if (!TClient.SerialEnabled) {
if (PinUsed(GPIO_TASMOTACLIENT_RXD) && PinUsed(GPIO_TASMOTACLIENT_TXD) &&
(PinUsed(GPIO_TASMOTACLIENT_RST) || PinUsed(GPIO_TASMOTACLIENT_RST_INV))) {
TasmotaClient_Serial = new TasmotaSerial(Pin(GPIO_TASMOTACLIENT_RXD), Pin(GPIO_TASMOTACLIENT_TXD), 1, 0, 200);
if (TasmotaClient_Serial->begin(USE_TASMOTA_CLIENT_SERIAL_SPEED)) {
if (TasmotaClient_Serial->hardwareSerial()) {
ClaimSerial();
}
TasmotaClient_Serial->setTimeout(100); // Theo 20200502 - increase from 50
if (PinUsed(GPIO_TASMOTACLIENT_RST_INV)) {
SetPin(Pin(GPIO_TASMOTACLIENT_RST_INV), GPIO_TASMOTACLIENT_RST);
TClient.inverted = HIGH;
}
pinMode(Pin(GPIO_TASMOTACLIENT_RST), OUTPUT);
TClient.SerialEnabled = true;
TasmotaClient_Reset();
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Enabled"));
}
}
}
if (TClient.SerialEnabled) { // All go for hardware now we need to detect features if there are any
TasmotaClient_sendCmnd(CMND_FEATURES, 0);
char buffer[32] = { 0 };
TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
memcpy(&TClientSettings, &buffer, sizeof(TClientSettings));
if (20191129 == TClientSettings.features_version) {
TClient.type = true;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u"), TClientSettings.features_version);
} else {
if ((!TClient.unsupported) && (TClientSettings.features_version > 0)) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("TCL: Version %u not supported!"), TClientSettings.features_version);
TClient.unsupported = true;
}
}
}
}
void TasmotaClient_Show(void) {
if ((TClient.type) && (TClientSettings.features.func_json_append)) {
char buffer[100];
TasmotaClient_sendCmnd(CMND_JSON, 0);
TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
uint8_t len = TasmotaClient_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
buffer[len] = '\0';
ResponseAppend_P(PSTR(",\"TasmotaClient\":%s"), buffer);
}
}
void TasmotaClient_sendCmnd(uint8_t cmnd, uint8_t param) {
TClientCommand.command = cmnd;
TClientCommand.parameter = param;
char buffer[sizeof(TClientCommand)+2];
buffer[0] = CMND_START;
memcpy(&buffer[1], &TClientCommand, sizeof(TClientCommand));
buffer[sizeof(TClientCommand)+1] = CMND_END;
TasmotaClient_Serial->flush(); // Theo 20200502
for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
TasmotaClient_Serial->write(buffer[ca]);
}
}
#define D_PRFX_CLIENT "Client"
#define D_CMND_CLIENT_RESET "Reset"
#define D_CMND_CLIENT_SEND "Send"
const char kTasmotaClientCommands[] PROGMEM = D_PRFX_CLIENT "|"
D_CMND_CLIENT_RESET "|" D_CMND_CLIENT_SEND;
void (* const TasmotaClientCommand[])(void) PROGMEM = {
&CmndClientReset, &CmndClientSend };
void CmndClientReset(void) {
TasmotaClient_Reset();
TClient.type = false; // Force redetection
TClient.waitstate = 7; // give it at least 3 seconds to restart from bootloader
TClient.unsupported = false; // Reset unsupported flag
ResponseCmndDone();
}
void CmndClientSend(void) {
if (0 < XdrvMailbox.data_len) {
TasmotaClient_sendCmnd(CMND_CLIENT_SEND, XdrvMailbox.data_len);
TasmotaClient_Serial->write(char(PARAM_DATA_START));
for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
TasmotaClient_Serial->write(XdrvMailbox.data[idx]);
}
TasmotaClient_Serial->write(char(PARAM_DATA_END));
}
ResponseCmndDone();
}
void TasmotaClient_ProcessIn(void) {
uint8_t cmnd = TasmotaClient_Serial->read();
if (CMND_START == cmnd) {
TasmotaClient_waitForSerialData(sizeof(TClientCommand),50);
uint8_t buffer[sizeof(TClientCommand)];
for (uint8_t idx = 0; idx < sizeof(TClientCommand); idx++) {
buffer[idx] = TasmotaClient_Serial->read();
}
TasmotaClient_Serial->read(); // read trailing byte of command
memcpy(&TClientCommand, &buffer, sizeof(TClientCommand));
char inbuf[TClientCommand.parameter+1];
TasmotaClient_waitForSerialData(TClientCommand.parameter, 50);
TasmotaClient_Serial->read(); // Read leading byte
for (uint8_t idx = 0; idx < TClientCommand.parameter; idx++) {
inbuf[idx] = TasmotaClient_Serial->read();
}
TasmotaClient_Serial->read(); // Read trailing byte
inbuf[TClientCommand.parameter] = '\0';
if (CMND_PUBLISH_TELE == TClientCommand.command) { // We need to publish stat/ with incoming stream as content
Response_P(PSTR("{\"TasmotaClient\":"));
ResponseAppend_P("%s", inbuf);
ResponseJsonEnd();
MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
XdrvRulesProcess();
}
if (CMND_EXECUTE_CMND == TClientCommand.command) { // We need to execute the incoming command
ExecuteCommand(inbuf, SRC_IGNORE);
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv31(uint8_t function) {
bool result = false;
switch (function) {
case FUNC_EVERY_100_MSECOND:
if (TClient.type) {
if (TasmotaClient_Serial->available()) {
TasmotaClient_ProcessIn();
}
if (TClientSettings.features.func_every_100_msecond) {
TasmotaClient_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
}
}
break;
case FUNC_EVERY_SECOND:
if ((TClient.type) && (TClientSettings.features.func_every_second)) {
TasmotaClient_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
}
TasmotaClient_Init();
break;
case FUNC_JSON_APPEND:
if ((TClient.type) && (TClientSettings.features.func_json_append)) {
TasmotaClient_Show();
}
break;
case FUNC_COMMAND:
result = DecodeCommand(kTasmotaClientCommands, TasmotaClientCommand);
break;
}
return result;
}
#endif // USE_TASMOTA_CLIENT

View File

@ -1,615 +0,0 @@
/*
xdrv_31_tasmota_slave.ino - Support for external microcontroller slave on serial
Copyright (C) 2020 Andre Thomas and Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_TASMOTA_SLAVE
/*********************************************************************************************\
* Tasmota slave
\*********************************************************************************************/
#define XDRV_31 31
#define CONST_STK_CRC_EOP 0x20
#define CMND_STK_GET_SYNC 0x30
#define CMND_STK_SET_DEVICE 0x42
#define CMND_STK_SET_DEVICE_EXT 0x45
#define CMND_STK_ENTER_PROGMODE 0x50
#define CMND_STK_LEAVE_PROGMODE 0x51
#define CMND_STK_LOAD_ADDRESS 0x55
#define CMND_STK_PROG_PAGE 0x64
/*************************************************\
* Tasmota Slave Specific Commands
\*************************************************/
#define CMND_START 0xFC
#define CMND_END 0xFD
#define CMND_FEATURES 0x01
#define CMND_JSON 0x02
#define CMND_FUNC_EVERY_SECOND 0x03
#define CMND_FUNC_EVERY_100_MSECOND 0x04
#define CMND_SLAVE_SEND 0x05
#define CMND_PUBLISH_TELE 0x06
#define CMND_EXECUTE_CMND 0x07
#define PARAM_DATA_START 0xFE
#define PARAM_DATA_END 0xFF
#include <TasmotaSerial.h>
/*
* Embedding class in here since its rather specific to Arduino bootloader
*/
class SimpleHexParse {
public:
SimpleHexParse(void);
uint8_t parseLine(char *hexline);
uint8_t ptr_l = 0;
uint8_t ptr_h = 0;
bool PageIsReady = false;
bool firstrun = true;
bool EndOfFile = false;
uint8_t FlashPage[128];
uint8_t FlashPageIdx = 0;
uint8_t layoverBuffer[16];
uint8_t layoverIdx = 0;
uint8_t getByte(char *hexline, uint8_t idx);
};
SimpleHexParse::SimpleHexParse(void)
{
}
uint8_t SimpleHexParse::parseLine(char *hexline)
{
if (layoverIdx) {
memcpy(&FlashPage[0], &layoverBuffer[0], layoverIdx);
FlashPageIdx = layoverIdx;
layoverIdx = 0;
}
uint8_t len = getByte(hexline, 1);
uint8_t addr_h = getByte(hexline, 2);
uint8_t addr_l = getByte(hexline, 3);
uint8_t rectype = getByte(hexline, 4);
for (uint8_t idx = 0; idx < len; idx++) {
if (FlashPageIdx < 128) {
FlashPage[FlashPageIdx] = getByte(hexline, idx+5);
FlashPageIdx++;
} else { // We have layover bytes
layoverBuffer[layoverIdx] = getByte(hexline, idx+5);
layoverIdx++;
}
}
if (1 == rectype) {
EndOfFile = true;
while (FlashPageIdx < 128) {
FlashPage[FlashPageIdx] = 0xFF;
FlashPageIdx++;
}
}
if (FlashPageIdx == 128) {
if (firstrun) {
firstrun = false;
} else {
ptr_l += 0x40;
if (ptr_l == 0) {
ptr_l = 0;
ptr_h++;
}
}
firstrun = false;
PageIsReady = true;
}
return 0;
}
uint8_t SimpleHexParse::getByte(char* hexline, uint8_t idx)
{
char buff[3];
buff[3] = '\0';
memcpy(&buff, &hexline[(idx*2)-1], 2);
return strtol(buff, 0, 16);
}
/*
* End of embedded class SimpleHexParse
*/
struct TSLAVE {
uint32_t spi_hex_size = 0;
uint32_t spi_sector_counter = 0;
uint8_t spi_sector_cursor = 0;
uint8_t inverted = LOW;
bool type = false;
bool flashing = false;
bool SerialEnabled = false;
uint8_t waitstate = 0; // We use this so that features detection does not slow down other stuff on startup
bool unsupported = false;
} TSlave;
typedef union {
uint32_t data;
struct {
uint32_t func_json_append : 1; // Slave supports providing a JSON for TELEPERIOD
uint32_t func_every_second : 1; // Slave supports receiving a FUNC_EVERY_SECOND callback with no response
uint32_t func_every_100_msecond : 1; // Slave supports receiving a FUNC_EVERY_100_MSECOND callback with no response
uint32_t func_slave_send : 1; // Slave supports receiving commands with "slave send xxx"
uint32_t spare4 : 1;
uint32_t spare5 : 1;
uint32_t spare6 : 1;
uint32_t spare7 : 1;
uint32_t spare8 : 1;
uint32_t spare9 : 1;
uint32_t spare10 : 1;
uint32_t spare11 : 1;
uint32_t spare12 : 1;
uint32_t spare13 : 1;
uint32_t spare14 : 1;
uint32_t spare15 : 1;
uint32_t spare16 : 1;
uint32_t spare17 : 1;
uint32_t spare18 : 1;
uint32_t spare19 : 1;
uint32_t spare20 : 1;
uint32_t spare21 : 1;
uint32_t spare22 : 1;
uint32_t spare23 : 1;
uint32_t spare24 : 1;
uint32_t spare25 : 1;
uint32_t spare26 : 1;
uint32_t spare27 : 1;
uint32_t spare28 : 1;
uint32_t spare29 : 1;
uint32_t spare30 : 1;
uint32_t spare31 : 1;
};
} TSlaveFeatureCfg;
/*
* The structure below must remain 4 byte aligned to be compatible with
* Tasmota as master
*/
struct TSLAVE_FEATURES {
uint32_t features_version;
TSlaveFeatureCfg features;
} TSlaveSettings;
struct TSLAVE_COMMAND {
uint8_t command;
uint8_t parameter;
uint8_t unused2;
uint8_t unused3;
} TSlaveCommand;
TasmotaSerial *TasmotaSlave_Serial;
uint32_t TasmotaSlave_FlashStart(void)
{
return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; // Stay on the safe side
}
uint8_t TasmotaSlave_UpdateInit(void)
{
TSlave.spi_hex_size = 0;
TSlave.spi_sector_counter = TasmotaSlave_FlashStart(); // Reset the pre-defined write address where firmware will temporarily be stored
TSlave.spi_sector_cursor = 0;
return 0;
}
void TasmotaSlave_Reset(void)
{
if (TSlave.SerialEnabled) {
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
delay(1);
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), TSlave.inverted);
delay(1);
digitalWrite(Pin(GPIO_TASMOTASLAVE_RST), !TSlave.inverted);
delay(5);
}
}
uint8_t TasmotaSlave_waitForSerialData(int dataCount, int timeout)
{
int timer = 0;
while (timer < timeout) {
if (TasmotaSlave_Serial->available() >= dataCount) {
return 1;
}
delay(1);
timer++;
}
return 0;
}
uint8_t TasmotaSlave_sendBytes(uint8_t* bytes, int count)
{
TasmotaSlave_Serial->write(bytes, count);
TasmotaSlave_waitForSerialData(2, 250);
uint8_t sync = TasmotaSlave_Serial->read();
uint8_t ok = TasmotaSlave_Serial->read();
if ((sync == 0x14) && (ok == 0x10)) {
return 1;
}
return 0;
}
uint8_t TasmotaSlave_execCmd(uint8_t cmd)
{
uint8_t bytes[] = { cmd, CONST_STK_CRC_EOP };
return TasmotaSlave_sendBytes(bytes, 2);
}
uint8_t TasmotaSlave_execParam(uint8_t cmd, uint8_t* params, int count)
{
uint8_t bytes[32];
bytes[0] = cmd;
int i = 0;
while (i < count) {
bytes[i + 1] = params[i];
i++;
}
bytes[i + 1] = CONST_STK_CRC_EOP;
return TasmotaSlave_sendBytes(bytes, i + 2);
}
uint8_t TasmotaSlave_exitProgMode(void)
{
return TasmotaSlave_execCmd(CMND_STK_LEAVE_PROGMODE); // Exit programming mode
}
uint8_t TasmotaSlave_SetupFlash(void)
{
uint8_t ProgParams[] = {0x86, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x03, 0xff, 0xff, 0xff, 0xff, 0x00, 0x80, 0x04, 0x00, 0x00, 0x00, 0x80, 0x00};
uint8_t ExtProgParams[] = {0x05, 0x04, 0xd7, 0xc2, 0x00};
TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_FLASH_SPEED);
if (TasmotaSlave_Serial->hardwareSerial()) {
ClaimSerial();
}
TasmotaSlave_Reset();
uint8_t timeout = 0;
uint8_t no_error = 0;
while (50 > timeout) {
if (TasmotaSlave_execCmd(CMND_STK_GET_SYNC)) {
timeout = 200;
no_error = 1;
}
timeout++;
delay(1);
}
if (no_error) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Found bootloader"));
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Bootloader could not be found"));
}
if (no_error) {
if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE, ProgParams, sizeof(ProgParams))) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (1)"));
}
}
if (no_error) {
if (TasmotaSlave_execParam(CMND_STK_SET_DEVICE_EXT, ExtProgParams, sizeof(ExtProgParams))) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Could not configure device for programming (2)"));
}
}
if (no_error) {
if (TasmotaSlave_execCmd(CMND_STK_ENTER_PROGMODE)) {
} else {
no_error = 0;
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Failed to put bootloader into programming mode"));
}
}
return no_error;
}
uint8_t TasmotaSlave_loadAddress(uint8_t adrHi, uint8_t adrLo)
{
uint8_t params[] = { adrLo, adrHi };
return TasmotaSlave_execParam(CMND_STK_LOAD_ADDRESS, params, sizeof(params));
}
void TasmotaSlave_FlashPage(uint8_t addr_h, uint8_t addr_l, uint8_t* data)
{
uint8_t Header[] = {CMND_STK_PROG_PAGE, 0x00, 0x80, 0x46};
TasmotaSlave_loadAddress(addr_h, addr_l);
TasmotaSlave_Serial->write(Header, 4);
for (int i = 0; i < 128; i++) {
TasmotaSlave_Serial->write(data[i]);
}
TasmotaSlave_Serial->write(CONST_STK_CRC_EOP);
TasmotaSlave_waitForSerialData(2, 250);
TasmotaSlave_Serial->read();
TasmotaSlave_Serial->read();
}
void TasmotaSlave_Flash(void)
{
bool reading = true;
uint32_t read = 0;
uint32_t processed = 0;
char thishexline[50];
uint8_t position = 0;
char* flash_buffer;
SimpleHexParse hexParse = SimpleHexParse();
if (!TasmotaSlave_SetupFlash()) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flashing aborted!"));
TSlave.flashing = false;
restart_flag = 2;
return;
}
flash_buffer = new char[SPI_FLASH_SEC_SIZE];
uint32_t flash_start = TasmotaSlave_FlashStart() * SPI_FLASH_SEC_SIZE;
while (reading) {
ESP.flashRead(flash_start + read, (uint32_t*)flash_buffer, SPI_FLASH_SEC_SIZE);
read = read + SPI_FLASH_SEC_SIZE;
if (read >= TSlave.spi_hex_size) {
reading = false;
}
for (uint32_t ca = 0; ca < SPI_FLASH_SEC_SIZE; ca++) {
processed++;
if ((processed <= TSlave.spi_hex_size) && (!hexParse.EndOfFile)) {
if (':' == flash_buffer[ca]) {
position = 0;
}
if (0x0D == flash_buffer[ca]) {
thishexline[position] = 0;
hexParse.parseLine(thishexline);
if (hexParse.PageIsReady) {
TasmotaSlave_FlashPage(hexParse.ptr_h, hexParse.ptr_l, hexParse.FlashPage);
hexParse.PageIsReady = false;
hexParse.FlashPageIdx = 0;
}
} else {
if (0x0A != flash_buffer[ca]) {
thishexline[position] = flash_buffer[ca];
position++;
}
}
}
}
}
TasmotaSlave_exitProgMode();
AddLog_P2(LOG_LEVEL_INFO, PSTR("TasmotaSlave: Flash done!"));
TSlave.flashing = false;
restart_flag = 2;
}
void TasmotaSlave_SetFlagFlashing(bool value)
{
TSlave.flashing = value;
}
bool TasmotaSlave_GetFlagFlashing(void)
{
return TSlave.flashing;
}
void TasmotaSlave_WriteBuffer(uint8_t *buf, size_t size)
{
if (0 == TSlave.spi_sector_cursor) { // Starting a new sector write so we need to erase it first
ESP.flashEraseSector(TSlave.spi_sector_counter);
}
TSlave.spi_sector_cursor++;
ESP.flashWrite((TSlave.spi_sector_counter * SPI_FLASH_SEC_SIZE) + ((TSlave.spi_sector_cursor-1)*2048), (uint32_t*)buf, size);
TSlave.spi_hex_size = TSlave.spi_hex_size + size;
if (2 == TSlave.spi_sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase
TSlave.spi_sector_cursor = 0;
TSlave.spi_sector_counter++;
}
}
void TasmotaSlave_Init(void)
{
if (TSlave.type) {
return;
}
if (10 > TSlave.waitstate) {
TSlave.waitstate++;
return;
}
if (!TSlave.SerialEnabled) {
if (PinUsed(GPIO_TASMOTASLAVE_RXD) && PinUsed(GPIO_TASMOTASLAVE_TXD) &&
(PinUsed(GPIO_TASMOTASLAVE_RST) || PinUsed(GPIO_TASMOTASLAVE_RST_INV))) {
TasmotaSlave_Serial = new TasmotaSerial(Pin(GPIO_TASMOTASLAVE_RXD), Pin(GPIO_TASMOTASLAVE_TXD), 1, 0, 200);
if (TasmotaSlave_Serial->begin(USE_TASMOTA_SLAVE_SERIAL_SPEED)) {
if (TasmotaSlave_Serial->hardwareSerial()) {
ClaimSerial();
}
TasmotaSlave_Serial->setTimeout(100); // Theo 20200502 - increase from 50
if (PinUsed(GPIO_TASMOTASLAVE_RST_INV)) {
SetPin(Pin(GPIO_TASMOTASLAVE_RST_INV), GPIO_TASMOTASLAVE_RST);
TSlave.inverted = HIGH;
}
pinMode(Pin(GPIO_TASMOTASLAVE_RST), OUTPUT);
TSlave.SerialEnabled = true;
TasmotaSlave_Reset();
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Enabled"));
}
}
}
if (TSlave.SerialEnabled) { // All go for hardware now we need to detect features if there are any
TasmotaSlave_sendCmnd(CMND_FEATURES, 0);
char buffer[32] = { 0 };
TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer));
uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer));
if (len) { AddLogBuffer(LOG_LEVEL_DEBUG_MORE, (uint8_t*)buffer, len); } // Theo 20200502 - DMP: 99 17 34 01 02 00 00 00
memcpy(&TSlaveSettings, &buffer, sizeof(TSlaveSettings));
if (20191129 == TSlaveSettings.features_version) {
TSlave.type = true;
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u"), TSlaveSettings.features_version);
} else {
if ((!TSlave.unsupported) && (TSlaveSettings.features_version > 0)) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("Tasmota Slave Version %u not supported!"), TSlaveSettings.features_version);
TSlave.unsupported = true;
}
}
}
}
void TasmotaSlave_Show(void)
{
if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
char buffer[100];
TasmotaSlave_sendCmnd(CMND_JSON, 0);
TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_START), buffer, sizeof(buffer)-1);
uint8_t len = TasmotaSlave_Serial->readBytesUntil(char(PARAM_DATA_END), buffer, sizeof(buffer)-1);
buffer[len] = '\0';
ResponseAppend_P(PSTR(",\"TasmotaSlave\":%s"), buffer);
}
}
void TasmotaSlave_sendCmnd(uint8_t cmnd, uint8_t param)
{
TSlaveCommand.command = cmnd;
TSlaveCommand.parameter = param;
char buffer[sizeof(TSlaveCommand)+2];
buffer[0] = CMND_START;
memcpy(&buffer[1], &TSlaveCommand, sizeof(TSlaveCommand));
buffer[sizeof(TSlaveCommand)+1] = CMND_END;
TasmotaSlave_Serial->flush(); // Theo 20200502
for (uint8_t ca = 0; ca < sizeof(buffer); ca++) {
TasmotaSlave_Serial->write(buffer[ca]);
}
}
#define D_PRFX_SLAVE "Slave"
#define D_CMND_SLAVE_RESET "Reset"
#define D_CMND_SLAVE_SEND "Send"
const char kTasmotaSlaveCommands[] PROGMEM = D_PRFX_SLAVE "|"
D_CMND_SLAVE_RESET "|" D_CMND_SLAVE_SEND;
void (* const TasmotaSlaveCommand[])(void) PROGMEM = {
&CmndTasmotaSlaveReset, &CmndTasmotaSlaveSend };
void CmndTasmotaSlaveReset(void)
{
TasmotaSlave_Reset();
TSlave.type = false; // Force redetection
TSlave.waitstate = 7; // give it at least 3 seconds to restart from bootloader
TSlave.unsupported = false; // Reset unsupported flag
ResponseCmndDone();
}
void CmndTasmotaSlaveSend(void)
{
if (0 < XdrvMailbox.data_len) {
TasmotaSlave_sendCmnd(CMND_SLAVE_SEND, XdrvMailbox.data_len);
TasmotaSlave_Serial->write(char(PARAM_DATA_START));
for (uint8_t idx = 0; idx < XdrvMailbox.data_len; idx++) {
TasmotaSlave_Serial->write(XdrvMailbox.data[idx]);
}
TasmotaSlave_Serial->write(char(PARAM_DATA_END));
}
ResponseCmndDone();
}
void TasmotaSlave_ProcessIn(void)
{
uint8_t cmnd = TasmotaSlave_Serial->read();
switch (cmnd) {
case CMND_START:
TasmotaSlave_waitForSerialData(sizeof(TSlaveCommand),50);
uint8_t buffer[sizeof(TSlaveCommand)];
for (uint8_t idx = 0; idx < sizeof(TSlaveCommand); idx++) {
buffer[idx] = TasmotaSlave_Serial->read();
}
TasmotaSlave_Serial->read(); // read trailing byte of command
memcpy(&TSlaveCommand, &buffer, sizeof(TSlaveCommand));
char inbuf[TSlaveCommand.parameter+1];
TasmotaSlave_waitForSerialData(TSlaveCommand.parameter, 50);
TasmotaSlave_Serial->read(); // Read leading byte
for (uint8_t idx = 0; idx < TSlaveCommand.parameter; idx++) {
inbuf[idx] = TasmotaSlave_Serial->read();
}
TasmotaSlave_Serial->read(); // Read trailing byte
inbuf[TSlaveCommand.parameter] = '\0';
if (CMND_PUBLISH_TELE == TSlaveCommand.command) { // We need to publish stat/ with incoming stream as content
Response_P(PSTR("{\"TasmotaSlave\":"));
ResponseAppend_P("%s", inbuf);
ResponseJsonEnd();
MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data);
XdrvRulesProcess();
}
if (CMND_EXECUTE_CMND == TSlaveCommand.command) { // We need to execute the incoming command
ExecuteCommand(inbuf, SRC_IGNORE);
}
break;
default:
break;
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv31(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_EVERY_100_MSECOND:
if (TSlave.type) {
if (TasmotaSlave_Serial->available()) {
TasmotaSlave_ProcessIn();
}
if (TSlaveSettings.features.func_every_100_msecond) {
TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_100_MSECOND, 0);
}
}
break;
case FUNC_EVERY_SECOND:
if ((TSlave.type) && (TSlaveSettings.features.func_every_second)) {
TasmotaSlave_sendCmnd(CMND_FUNC_EVERY_SECOND, 0);
}
TasmotaSlave_Init();
break;
case FUNC_JSON_APPEND:
if ((TSlave.type) && (TSlaveSettings.features.func_json_append)) {
TasmotaSlave_Show();
}
break;
case FUNC_COMMAND:
result = DecodeCommand(kTasmotaSlaveCommands, TasmotaSlaveCommand);
break;
}
return result;
}
#endif // USE_TASMOTA_SLAVE

View File

@ -1331,7 +1331,7 @@ void ThermostatGetLocalSensor(uint8_t ctr_output) {
DynamicJsonBuffer jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((const char*)mqtt_data);
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])) ) ) {
int16_t value = (int16_t)(CharToFloat(value_c) * 10);
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.network_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

Some files were not shown because too many files have changed in this diff Show More