mirror of https://github.com/arendst/Tasmota.git
Merge branch 'development' into pre-release
This commit is contained in:
commit
ae7193d72c
|
@ -147,6 +147,7 @@ People helping to keep the show on the road:
|
|||
- Christian Staars for NRF24L01 and HM-10 Bluetooth sensor support
|
||||
- Paul Diem for UDP Group communication support
|
||||
- Jörg Schüler-Maroldt for his initial ESP32 port
|
||||
- Javier Arigita for his thermostat driver
|
||||
- Many more providing Tips, Wips, Pocs, PRs and Donations
|
||||
|
||||
## License
|
||||
|
|
|
@ -364,8 +364,12 @@ const unsigned char lut_partial_update[] =
|
|||
#define PIN_OUT_SET 0x60000304
|
||||
#define PIN_OUT_CLEAR 0x60000308
|
||||
|
||||
#define PWRITE xdigitalWrite
|
||||
|
||||
#ifdef ESP32
|
||||
#define SSPI_USEANYPIN 1
|
||||
#define PWRITE digitalWrite
|
||||
#else
|
||||
#define PWRITE ydigitalWrite
|
||||
#endif
|
||||
|
||||
#ifndef SSPI_USEANYPIN
|
||||
// uses about 2.75 usecs, 365 kb /sec
|
||||
|
@ -388,6 +392,7 @@ void ICACHE_RAM_ATTR Epd::fastSPIwrite(uint8_t d,uint8_t dc) {
|
|||
}
|
||||
#else
|
||||
|
||||
#ifndef ESP32
|
||||
extern void ICACHE_RAM_ATTR xdigitalWrite(uint8_t pin, uint8_t val) {
|
||||
//stopWaveform(pin);
|
||||
if(pin < 16){
|
||||
|
@ -398,6 +403,7 @@ extern void ICACHE_RAM_ATTR xdigitalWrite(uint8_t pin, uint8_t val) {
|
|||
else GP16O &= ~1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// about 13 us => 76 kb / sec
|
||||
// can use any pin
|
||||
|
|
|
@ -130,14 +130,14 @@ int Epd42::Init(void) {
|
|||
SendCommand(PANEL_SETTING);
|
||||
// SendData(0xbf); // KW-BF KWR-AF BWROTP 0f
|
||||
// SendData(0x0b);
|
||||
// SendData(0x0F); //300x400 Red mode, LUT from OTP
|
||||
// SendData(0x1F); //300x400 B/W mode, LUT from OTP
|
||||
SendData(0x3F); //300x400 B/W mode, LUT set by register
|
||||
// SendData(0x2F); //300x400 Red mode, LUT set by register
|
||||
// SendData(0x0F); //300x400 Red mode, LUT from OTP
|
||||
// SendData(0x1F); //300x400 B/W mode, LUT from OTP
|
||||
SendData(0x3F); //300x400 B/W mode, LUT set by register
|
||||
// SendData(0x2F); //300x400 Red mode, LUT set by register
|
||||
|
||||
SendCommand(PLL_CONTROL);
|
||||
SendData(0x3C); // 3A 100Hz 29 150Hz 39 200Hz 31 171Hz 3C 50Hz (default) 0B 10Hz
|
||||
//SendData(0x0B); //0B is 10Hz
|
||||
//SendData(0x0B); //0B is 10Hz
|
||||
/* EPD hardware init end */
|
||||
return 0;
|
||||
}
|
||||
|
@ -502,12 +502,15 @@ const unsigned char lut_wb_quick[] PROGMEM =
|
|||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define PIN_OUT_SET 0x60000304
|
||||
#define PIN_OUT_CLEAR 0x60000308
|
||||
|
||||
#ifdef ESP32
|
||||
#define SSPI_USEANYPIN 1
|
||||
#define PWRITE digitalWrite
|
||||
#else
|
||||
#define PWRITE ydigitalWrite
|
||||
#endif
|
||||
|
||||
#ifndef SSPI_USEANYPIN
|
||||
// uses about 2.75 usecs, 365 kb /sec
|
||||
|
@ -530,6 +533,7 @@ void ICACHE_RAM_ATTR Epd42::fastSPIwrite(uint8_t d,uint8_t dc) {
|
|||
}
|
||||
#else
|
||||
|
||||
#ifndef ESP32
|
||||
extern void ICACHE_RAM_ATTR ydigitalWrite(uint8_t pin, uint8_t val) {
|
||||
//stopWaveform(pin);
|
||||
if(pin < 16){
|
||||
|
@ -540,6 +544,7 @@ extern void ICACHE_RAM_ATTR ydigitalWrite(uint8_t pin, uint8_t val) {
|
|||
else GP16O &= ~1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// about 13 us => 76 kb / sec
|
||||
// can use any pin
|
||||
void Epd42::fastSPIwrite(uint8_t d,uint8_t dc) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
- Change default PWM Frequency to 977 Hz from 223 Hz
|
||||
- Change minimum PWM Frequency from 100 Hz to 40 Hz
|
||||
- Change PWM updated to the latest version of Arduino PR #7231
|
||||
- Change Philips Hue emulation now exposes modelId and manufacturerId
|
||||
|
||||
### 8.2.0.5 20200425
|
||||
|
||||
|
|
|
@ -675,13 +675,12 @@
|
|||
#define THERMOSTAT_SENSOR_NAME "DS18B20" // Name of the local sensor to be used
|
||||
#define THERMOSTAT_RELAY_NUMBER 1 // Default output relay number for the first controller (+i for following ones)
|
||||
#define THERMOSTAT_SWITCH_NUMBER 1 // Default input switch number for the first controller (+i for following ones)
|
||||
#define THERMOSTAT_TIME_ALLOW_RAMPUP 300 // Default time in seconds after last target update to allow ramp-up controller phase in minutes
|
||||
#define THERMOSTAT_TIME_ALLOW_RAMPUP 300 // Default time after last target update to allow ramp-up controller phase in minutes
|
||||
#define THERMOSTAT_TIME_RAMPUP_MAX 960 // Default time maximum ramp-up controller duration in minutes
|
||||
#define THERMOSTAT_TIME_RAMPUP_CYCLE 1800 // Default time ramp-up cycle in seconds
|
||||
#define THERMOSTAT_TIME_RAMPUP_CYCLE 30 // Default time ramp-up cycle in minutes
|
||||
#define THERMOSTAT_TIME_SENS_LOST 30 // Maximum time w/o sensor update to set it as lost in minutes
|
||||
#define THERMOSTAT_TEMP_SENS_NUMBER 1 // Default temperature sensor number
|
||||
#define THERMOSTAT_TIME_MANUAL_TO_AUTO 60 // Default time without input switch active to change from manual to automatic in minutes
|
||||
#define THERMOSTAT_TIME_ON_LIMIT 120 // Default maximum time with output active in minutes
|
||||
#define THERMOSTAT_TIME_RESET 12000 // Default reset time of the PI controller in seconds
|
||||
#define THERMOSTAT_TIME_PI_CYCLE 30 // Default cycle time for the thermostat controller in minutes
|
||||
#define THERMOSTAT_TIME_MAX_ACTION 20 // Default maximum thermostat time per cycle in minutes
|
||||
|
|
|
@ -638,7 +638,7 @@ float ConvertHumidity(float h)
|
|||
|
||||
float CalcTempHumToDew(float t, float h)
|
||||
{
|
||||
if (isnan(h) || isnan(t)) { return 0.0; }
|
||||
if (isnan(h) || isnan(t)) { return NAN; }
|
||||
|
||||
if (Settings.flag.temperature_conversion) { // SetOption8 - Switch between Celsius or Fahrenheit
|
||||
t = (t - 32) / 1.8; // Celsius
|
||||
|
@ -1863,3 +1863,62 @@ void AddLogBufferSize(uint32_t loglevel, uint8_t *buffer, uint32_t count, uint32
|
|||
}
|
||||
AddLog(loglevel);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* JSON parsing
|
||||
\*********************************************************************************************/
|
||||
|
||||
// does the character needs to be escaped, and if so with which character
|
||||
char escapeJSONChar(char c) {
|
||||
if ((c == '\"') || (c == '\\')) {
|
||||
return c;
|
||||
}
|
||||
if (c == '\n') { return 'n'; }
|
||||
if (c == '\t') { return 't'; }
|
||||
if (c == '\r') { return 'r'; }
|
||||
if (c == '\f') { return 'f'; }
|
||||
if (c == '\b') { return 'b'; }
|
||||
return 0;
|
||||
}
|
||||
|
||||
String escapeJSONString(const char *str) {
|
||||
String r("");
|
||||
if (nullptr == str) { return r; }
|
||||
|
||||
bool needs_escape = false;
|
||||
size_t len_out = 1;
|
||||
const char * c = str;
|
||||
|
||||
while (*c) {
|
||||
if (escapeJSONChar(*c)) {
|
||||
len_out++;
|
||||
needs_escape = true;
|
||||
}
|
||||
c++;
|
||||
len_out++;
|
||||
}
|
||||
|
||||
if (needs_escape) {
|
||||
// we need to escape some chars
|
||||
// allocate target buffer
|
||||
r.reserve(len_out);
|
||||
c = str;
|
||||
char *d = r.begin();
|
||||
while (*c) {
|
||||
char c2 = escapeJSONChar(*c);
|
||||
if (c2) {
|
||||
c++;
|
||||
*d++ = '\\';
|
||||
*d++ = c2;
|
||||
} else {
|
||||
*d++ = *c++;
|
||||
}
|
||||
}
|
||||
*d = 0; // add NULL terminator
|
||||
r = (char*) r.begin(); // assign the buffer to the string
|
||||
} else {
|
||||
r = str;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
|
@ -1227,6 +1227,17 @@ void SerialInput(void)
|
|||
delay(0);
|
||||
serial_in_byte = Serial.read();
|
||||
|
||||
if (0 == serial_in_byte_counter) {
|
||||
serial_buffer_overrun = false;
|
||||
}
|
||||
else if ((serial_in_byte_counter == INPUT_BUFFER_SIZE)
|
||||
#ifdef ESP8266
|
||||
// || Serial.hasOverrun() // Default ESP8266 Serial buffer size is 256. Tasmota increases to INPUT_BUFFER_SIZE
|
||||
#endif
|
||||
) {
|
||||
serial_buffer_overrun = true;
|
||||
}
|
||||
|
||||
#ifdef ESP8266
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Sonoff dual and ch4 19200 baud serial interface
|
||||
|
@ -1255,7 +1266,7 @@ void SerialInput(void)
|
|||
if (serial_in_byte_counter < INPUT_BUFFER_SIZE -1) { // Add char to string if it still fits
|
||||
serial_in_buffer[serial_in_byte_counter++] = serial_in_byte;
|
||||
} else {
|
||||
serial_in_byte_counter = 0;
|
||||
serial_buffer_overrun = true; // Signal overrun but continue reading input to flush until '\n' (EOL)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1292,8 +1303,12 @@ void SerialInput(void)
|
|||
if (!Settings.flag.mqtt_serial && (serial_in_byte == '\n')) { // CMND_SERIALSEND and CMND_SERIALLOG
|
||||
serial_in_buffer[serial_in_byte_counter] = 0; // Serial data completed
|
||||
seriallog_level = (Settings.seriallog_level < LOG_LEVEL_INFO) ? (uint8_t)LOG_LEVEL_INFO : Settings.seriallog_level;
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
|
||||
ExecuteCommand(serial_in_buffer, SRC_SERIAL);
|
||||
if (serial_buffer_overrun) {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "Serial buffer overrun"));
|
||||
} else {
|
||||
AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_COMMAND "%s"), serial_in_buffer);
|
||||
ExecuteCommand(serial_in_buffer, SRC_SERIAL);
|
||||
}
|
||||
serial_in_byte_counter = 0;
|
||||
serial_polling_window = 0;
|
||||
Serial.flush();
|
||||
|
|
|
@ -124,7 +124,7 @@ const uint16_t SYSLOG_TIMER = 600; // Seconds to restore syslog_level
|
|||
const uint16_t SERIALLOG_TIMER = 600; // Seconds to disable SerialLog
|
||||
const uint8_t OTA_ATTEMPTS = 5; // Number of times to try fetching the new firmware
|
||||
|
||||
const uint16_t INPUT_BUFFER_SIZE = 520; // Max number of characters in (serial and http) command buffer
|
||||
const uint16_t INPUT_BUFFER_SIZE = 520; // Max number of characters in serial command buffer
|
||||
const uint16_t FLOATSZ = 16; // Max number of characters in float result from dtostrfd (max 32)
|
||||
const uint16_t CMDSZ = 24; // Max number of characters in command
|
||||
const uint16_t TOPSZ = 151; // Max number of characters in topic string
|
||||
|
|
|
@ -156,7 +156,8 @@ uint8_t last_source = 0; // Last command source
|
|||
uint8_t shutters_present = 0; // Number of actual define shutters
|
||||
uint8_t prepped_loglevel = 0; // Delayed log level message
|
||||
//uint8_t mdns_delayed_start = 0; // mDNS delayed start
|
||||
bool serial_local = false; // Handle serial locally;
|
||||
bool serial_local = false; // Handle serial locally
|
||||
bool serial_buffer_overrun = false; // Serial buffer overrun
|
||||
bool fallback_topic_flag = false; // Use Topic or FallbackTopic
|
||||
bool backlog_mutex = false; // Command backlog pending
|
||||
bool interlock_mutex = false; // Interlock power command pending
|
||||
|
@ -215,6 +216,7 @@ void setup(void)
|
|||
RtcRebootSave();
|
||||
|
||||
Serial.begin(APP_BAUDRATE);
|
||||
Serial.setRxBufferSize(INPUT_BUFFER_SIZE); // Default is 256 chars
|
||||
seriallog_level = LOG_LEVEL_INFO; // Allow specific serial messages until config loaded
|
||||
|
||||
snprintf_P(my_version, sizeof(my_version), PSTR("%d.%d.%d"), VERSION >> 24 & 0xff, VERSION >> 16 & 0xff, VERSION >> 8 & 0xff); // Release version 6.3.0
|
||||
|
|
|
@ -1992,12 +1992,21 @@ void CmndRule(void)
|
|||
}
|
||||
Rules.triggers[index -1] = 0; // Reset once flag
|
||||
}
|
||||
String rule = GetRule(index - 1);
|
||||
size_t rule_len = rule.length();
|
||||
if (rule_len >= MAX_RULE_SIZE) {
|
||||
// we need to split the rule in chunks
|
||||
rule = rule.substring(0, MAX_RULE_SIZE);
|
||||
rule += F("...");
|
||||
}
|
||||
// snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}"),
|
||||
// XdrvMailbox.command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)),
|
||||
// GetStateText(bitRead(Settings.rule_stop, index -1)), sizeof(Settings.rules[index -1]) - strlen(Settings.rules[index -1]) -1, Settings.rules[index -1]);
|
||||
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Free\":%d,\"Rules\":\"%s\"}"),
|
||||
snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s%d\":\"%s\",\"Once\":\"%s\",\"StopOnError\":\"%s\",\"Length\":%d,\"Free\":%d,\"Rules\":\"%s\"}"),
|
||||
XdrvMailbox.command, index, GetStateText(bitRead(Settings.rule_enabled, index -1)), GetStateText(bitRead(Settings.rule_once, index -1)),
|
||||
GetStateText(bitRead(Settings.rule_stop, index -1)), sizeof(Settings.rules[0]) - GetRuleLenStorage(index - 1), GetRule(index - 1).c_str());
|
||||
GetStateText(bitRead(Settings.rule_stop, index -1)),
|
||||
rule_len, MAX_RULE_SIZE - GetRuleLenStorage(index - 1),
|
||||
escapeJSONString(rule.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1879,6 +1879,19 @@ chknext:
|
|||
len=0;
|
||||
goto strexit;
|
||||
}
|
||||
#ifdef ESP32
|
||||
if (!strncmp(vname,"sf(",3)) {
|
||||
lp+=2;
|
||||
lp=GetNumericResult(lp,OPER_EQU,&fvar,0);
|
||||
if (fvar<80) fvar=80;
|
||||
if (fvar>240) fvar=240;
|
||||
setCpuFrequencyMhz(fvar);
|
||||
fvar=getCpuFrequencyMhz();
|
||||
lp++;
|
||||
len=0;
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_TIMERS) && defined(USE_SUNRISE)
|
||||
if (!strncmp(vname,"sunrise",7)) {
|
||||
fvar=SunMinutes(0);
|
||||
|
@ -2093,7 +2106,7 @@ chknext:
|
|||
len=0;
|
||||
goto exit;
|
||||
}
|
||||
#endif
|
||||
#endif //ESP32, USE_WEBCAM
|
||||
if (!strncmp(vname,"wday",4)) {
|
||||
fvar=RtcTime.day_of_week;
|
||||
goto exit;
|
||||
|
@ -2692,11 +2705,13 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) {
|
|||
return -99;
|
||||
}
|
||||
|
||||
DynamicJsonBuffer jsonBuffer; // on heap
|
||||
JsonObject &jobj=jsonBuffer.parseObject(js);
|
||||
JsonObject *jo;
|
||||
if (js) jo=&jobj;
|
||||
else jo=0;
|
||||
JsonObject *jo=0;
|
||||
|
||||
if (js) {
|
||||
DynamicJsonBuffer jsonBuffer; // on heap
|
||||
JsonObject &jobj=jsonBuffer.parseObject(js);
|
||||
jo=&jobj;
|
||||
}
|
||||
|
||||
char *lp=glob_script_mem.scriptptr;
|
||||
|
||||
|
@ -5119,6 +5134,8 @@ bool RulesProcessEvent(char *json_event) {
|
|||
#ifdef USE_SCRIPT_TASK
|
||||
uint16_t task_timer1;
|
||||
uint16_t task_timer2;
|
||||
TaskHandle_t task_t1;
|
||||
TaskHandle_t task_t2;
|
||||
|
||||
void script_task1(void *arg) {
|
||||
while (1) {
|
||||
|
@ -5143,14 +5160,16 @@ void script_task2(void *arg) {
|
|||
|
||||
uint32_t scripter_create_task(uint32_t num, uint32_t time, uint32_t core) {
|
||||
//return 0;
|
||||
BaseType_t res=0;
|
||||
if (core>1) {core = 1;}
|
||||
BaseType_t res = 0;
|
||||
if (core > 1) { core = 1; }
|
||||
if (num == 1) {
|
||||
res = xTaskCreatePinnedToCore(script_task1, "T 1", STASK_STACK, NULL, STASK_PRIO, NULL, core);
|
||||
task_timer1=time;
|
||||
if (task_t1) { vTaskDelete(task_t1); }
|
||||
res = xTaskCreatePinnedToCore(script_task1, "T1", STASK_STACK, NULL, STASK_PRIO, &task_t1, core);
|
||||
task_timer1 = time;
|
||||
} else {
|
||||
res = xTaskCreatePinnedToCore(script_task2, "T 2", STASK_STACK, NULL, STASK_PRIO, NULL, core);
|
||||
task_timer2=time;
|
||||
if (task_t2) { vTaskDelete(task_t2); }
|
||||
res = xTaskCreatePinnedToCore(script_task2, "T2", STASK_STACK, NULL, STASK_PRIO, &task_t2, core);
|
||||
task_timer2 = time;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -144,9 +144,9 @@ const char HUE_LIGHTS_STATUS_JSON1_SUFFIX[] PROGMEM =
|
|||
const char HUE_LIGHTS_STATUS_JSON2[] PROGMEM =
|
||||
",\"type\":\"Extended color light\","
|
||||
"\"name\":\"%s\","
|
||||
"\"modelid\":\"LCT007\","
|
||||
"\"uniqueid\":\"%s\","
|
||||
"\"swversion\":\"5.50.1.19085\"}";
|
||||
"\"modelid\":\"%s\","
|
||||
"\"manufacturername\":\"%s\","
|
||||
"\"uniqueid\":\"%s\"}";
|
||||
const char HUE_GROUP0_STATUS_JSON[] PROGMEM =
|
||||
"{\"name\":\"Group 0\","
|
||||
"\"lights\":[{l1],"
|
||||
|
@ -358,7 +358,7 @@ bool HueActive(uint8_t device) {
|
|||
|
||||
void HueLightStatus2(uint8_t device, String *response)
|
||||
{
|
||||
const size_t buf_size = 192;
|
||||
const size_t buf_size = 300;
|
||||
char * buf = (char*) malloc(buf_size);
|
||||
const size_t max_name_len = 32;
|
||||
char fname[max_name_len + 1];
|
||||
|
@ -376,7 +376,11 @@ void HueLightStatus2(uint8_t device, String *response)
|
|||
}
|
||||
fname[fname_len] = 0x00;
|
||||
}
|
||||
snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON2, fname, GetHueDeviceId(device).c_str());
|
||||
snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON2,
|
||||
escapeJSONString(fname).c_str(),
|
||||
escapeJSONString(Settings.user_template_name).c_str(),
|
||||
PSTR("Tasmota"),
|
||||
GetHueDeviceId(device).c_str());
|
||||
*response += buf;
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
@ -127,6 +127,7 @@ public:
|
|||
void setFriendlyName(uint16_t shortaddr, const char * str);
|
||||
const char * getFriendlyName(uint16_t shortaddr) const;
|
||||
const char * getModelId(uint16_t shortaddr) const;
|
||||
const char * getManufacturerId(uint16_t shortaddr) const;
|
||||
void setReachable(uint16_t shortaddr, bool reachable);
|
||||
|
||||
// get next sequence number for (increment at each all)
|
||||
|
@ -589,6 +590,15 @@ const char * Z_Devices::getModelId(uint16_t shortaddr) const {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const char * Z_Devices::getManufacturerId(uint16_t shortaddr) const {
|
||||
int32_t found = findShortAddr(shortaddr);
|
||||
if (found >= 0) {
|
||||
const Z_Device & device = devicesAt(found);
|
||||
return device.manufacturerId;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Z_Devices::setReachable(uint16_t shortaddr, bool reachable) {
|
||||
Z_Device & device = getShortAddr(shortaddr);
|
||||
if (&device == nullptr) { return; } // don't crash if not found
|
||||
|
|
|
@ -75,16 +75,21 @@ void HueLightStatus1Zigbee(uint16_t shortaddr, uint8_t local_light_subtype, Stri
|
|||
|
||||
void HueLightStatus2Zigbee(uint16_t shortaddr, String *response)
|
||||
{
|
||||
const size_t buf_size = 192;
|
||||
const size_t buf_size = 300;
|
||||
char * buf = (char*) malloc(buf_size);
|
||||
|
||||
const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr);
|
||||
const char * modelId = zigbee_devices.getModelId(shortaddr);
|
||||
const char * manufacturerId = zigbee_devices.getManufacturerId(shortaddr);
|
||||
char shortaddrname[8];
|
||||
snprintf_P(shortaddrname, sizeof(shortaddrname), PSTR("0x%04X"), shortaddr);
|
||||
|
||||
snprintf_P(buf, buf_size, HUE_LIGHTS_STATUS_JSON2,
|
||||
(friendlyName) ? friendlyName : shortaddrname,
|
||||
(friendlyName) ? escapeJSONString(friendlyName).c_str() : shortaddrname,
|
||||
(modelId) ? escapeJSONString(modelId).c_str() : PSTR("Unknown"),
|
||||
(manufacturerId) ? escapeJSONString(manufacturerId).c_str() : PSTR("Tasmota"),
|
||||
GetHueDeviceId(shortaddr).c_str());
|
||||
|
||||
*response += buf;
|
||||
free(buf);
|
||||
}
|
||||
|
|
|
@ -134,18 +134,18 @@ const char kThermostatCommands[] PROGMEM = "|" D_CMND_THERMOSTATMODESET "|" D_CM
|
|||
D_CMND_TEMPFROSTPROTECTSET "|" D_CMND_CONTROLLERMODESET "|" D_CMND_INPUTSWITCHSET "|" D_CMND_INPUTSWITCHUSE "|"
|
||||
D_CMND_OUTPUTRELAYSET "|" D_CMND_TIMEALLOWRAMPUPSET "|" D_CMND_TEMPFORMATSET "|" D_CMND_TEMPMEASUREDSET "|"
|
||||
D_CMND_TEMPTARGETSET "|" D_CMND_TEMPMEASUREDGRDREAD "|" D_CMND_SENSORINPUTSET "|" D_CMND_STATEEMERGENCYSET "|"
|
||||
D_CMND_TIMEMANUALTOAUTOSET "|" D_CMND_TIMEONLIMITSET "|" D_CMND_PROPBANDSET "|" D_CMND_TIMERESETSET "|"
|
||||
D_CMND_TIMEPICYCLESET "|" D_CMND_TEMPANTIWINDUPRESETSET "|" D_CMND_TEMPHYSTSET "|" D_CMND_TIMEMAXACTIONSET "|"
|
||||
D_CMND_TIMEMINACTIONSET "|" D_CMND_TIMEMINTURNOFFACTIONSET "|" D_CMND_TEMPRUPDELTINSET "|" D_CMND_TEMPRUPDELTOUTSET "|"
|
||||
D_CMND_TIMERAMPUPMAXSET "|" D_CMND_TIMERAMPUPCYCLESET "|" D_CMND_TEMPRAMPUPPIACCERRSET "|" D_CMND_TIMEPIPROPORTREAD "|"
|
||||
D_CMND_TIMEPIINTEGRREAD "|" D_CMND_TIMESENSLOSTSET "|" D_CMND_DIAGNOSTICMODESET;
|
||||
D_CMND_TIMEMANUALTOAUTOSET "|" D_CMND_PROPBANDSET "|" D_CMND_TIMERESETSET "|" D_CMND_TIMEPICYCLESET "|"
|
||||
D_CMND_TEMPANTIWINDUPRESETSET "|" D_CMND_TEMPHYSTSET "|" D_CMND_TIMEMAXACTIONSET "|" D_CMND_TIMEMINACTIONSET "|"
|
||||
D_CMND_TIMEMINTURNOFFACTIONSET "|" D_CMND_TEMPRUPDELTINSET "|" D_CMND_TEMPRUPDELTOUTSET "|" D_CMND_TIMERAMPUPMAXSET "|"
|
||||
D_CMND_TIMERAMPUPCYCLESET "|" D_CMND_TEMPRAMPUPPIACCERRSET "|" D_CMND_TIMEPIPROPORTREAD "|" D_CMND_TIMEPIINTEGRREAD "|"
|
||||
D_CMND_TIMESENSLOSTSET "|" D_CMND_DIAGNOSTICMODESET;
|
||||
|
||||
void (* const ThermostatCommand[])(void) PROGMEM = {
|
||||
&CmndThermostatModeSet, &CmndClimateModeSet, &CmndTempFrostProtectSet, &CmndControllerModeSet, &CmndInputSwitchSet,
|
||||
&CmndInputSwitchUse, &CmndOutputRelaySet, &CmndTimeAllowRampupSet, &CmndTempFormatSet, &CmndTempMeasuredSet,
|
||||
&CmndTempTargetSet, &CmndTempMeasuredGrdRead, &CmndSensorInputSet, &CmndStateEmergencySet, &CmndTimeManualToAutoSet,
|
||||
&CmndTimeOnLimitSet, &CmndPropBandSet, &CmndTimeResetSet, &CmndTimePiCycleSet, &CmndTempAntiWindupResetSet,
|
||||
&CmndTempHystSet, &CmndTimeMaxActionSet, &CmndTimeMinActionSet, &CmndTimeMinTurnoffActionSet, &CmndTempRupDeltInSet,
|
||||
&CmndPropBandSet, &CmndTimeResetSet, &CmndTimePiCycleSet, &CmndTempAntiWindupResetSet, &CmndTempHystSet,
|
||||
&CmndTimeMaxActionSet, &CmndTimeMinActionSet, &CmndTimeMinTurnoffActionSet, &CmndTempRupDeltInSet,
|
||||
&CmndTempRupDeltOutSet, &CmndTimeRampupMaxSet, &CmndTimeRampupCycleSet, &CmndTempRampupPiAccErrSet,
|
||||
&CmndTimePiProportRead, &CmndTimePiIntegrRead, &CmndTimeSensLostSet, &CmndDiagnosticModeSet };
|
||||
|
||||
|
@ -183,16 +183,15 @@ struct THERMOSTAT {
|
|||
int16_t temp_rampup_start = 0; // Temperature at start of ramp-up controller in tenths of degrees celsius
|
||||
int16_t temp_rampup_cycle = 0; // Temperature set at the beginning of each ramp-up cycle in tenths of degrees
|
||||
uint16_t time_rampup_max = THERMOSTAT_TIME_RAMPUP_MAX; // Time maximum ramp-up controller duration in minutes
|
||||
uint16_t time_rampup_cycle = THERMOSTAT_TIME_RAMPUP_CYCLE; // Time ramp-up cycle in seconds
|
||||
uint16_t time_rampup_cycle = THERMOSTAT_TIME_RAMPUP_CYCLE; // Time ramp-up cycle in minutes
|
||||
uint16_t time_allow_rampup = THERMOSTAT_TIME_ALLOW_RAMPUP; // Time in minutes after last target update to allow ramp-up controller phase
|
||||
uint16_t time_sens_lost = THERMOSTAT_TIME_SENS_LOST; // Maximum time w/o sensor update to set it as lost
|
||||
uint16_t time_sens_lost = THERMOSTAT_TIME_SENS_LOST; // Maximum time w/o sensor update to set it as lost in minutes
|
||||
uint16_t time_manual_to_auto = THERMOSTAT_TIME_MANUAL_TO_AUTO; // Time without input switch active to change from manual to automatic in minutes
|
||||
uint16_t time_on_limit = THERMOSTAT_TIME_ON_LIMIT; // Maximum time with output active in minutes
|
||||
uint16_t time_pi_cycle = THERMOSTAT_TIME_PI_CYCLE; // Cycle time for the thermostat controller in seconds
|
||||
uint32_t time_reset = THERMOSTAT_TIME_RESET; // Reset time of the PI controller in seconds
|
||||
uint16_t time_pi_cycle = THERMOSTAT_TIME_PI_CYCLE; // Cycle time for the thermostat controller in minutes
|
||||
uint16_t time_max_action = THERMOSTAT_TIME_MAX_ACTION; // Maximum thermostat time per cycle in minutes
|
||||
uint16_t time_min_action = THERMOSTAT_TIME_MIN_ACTION; // Minimum thermostat time per cycle in minutes
|
||||
uint16_t time_min_turnoff_action = THERMOSTAT_TIME_MIN_TURNOFF_ACTION; // Minimum turnoff time in minutes, below it the thermostat will be held on
|
||||
uint16_t time_min_turnoff_action = THERMOSTAT_TIME_MIN_TURNOFF_ACTION; // Minimum turnoff time in minutes, below it the thermostat will stay on
|
||||
uint8_t temp_reset_anti_windup = THERMOSTAT_TEMP_RESET_ANTI_WINDUP; // Range where reset antiwindup is disabled, in tenths of degrees celsius
|
||||
int8_t temp_hysteresis = THERMOSTAT_TEMP_HYSTERESIS; // Range hysteresis for temperature PI controller, in tenths of degrees celsius
|
||||
uint8_t temp_frost_protect = THERMOSTAT_TEMP_FROST_PROTECT; // Minimum temperature for frost protection, in tenths of degrees celsius
|
||||
|
@ -605,7 +604,7 @@ void ThermostatCalculatePI(uint8_t ctr_output)
|
|||
|
||||
// Antiwindup of the integrator
|
||||
// If integral calculation is bigger than cycle time, adjust result
|
||||
// to the cycle time and error will not be cummulated]]
|
||||
// to the cycle time and error will not be cummulated
|
||||
if (Thermostat[ctr_output].time_integral_pi > ((uint32_t)Thermostat[ctr_output].time_pi_cycle * 60)) {
|
||||
Thermostat[ctr_output].time_integral_pi = ((uint32_t)Thermostat[ctr_output].time_pi_cycle * 60);
|
||||
}
|
||||
|
@ -616,7 +615,7 @@ void ThermostatCalculatePI(uint8_t ctr_output)
|
|||
|
||||
// Antiwindup of the output
|
||||
// If result is bigger than cycle time, the result will be adjusted
|
||||
// to the cylce time minus safety time and error will not be cummulated]]
|
||||
// to the cylce time minus safety time and error will not be cummulated
|
||||
if (Thermostat[ctr_output].time_total_pi >= ((int32_t)Thermostat[ctr_output].time_pi_cycle * 60)) {
|
||||
// Limit to cycle time //at least switch down a minimum time
|
||||
Thermostat[ctr_output].time_total_pi = ((int32_t)Thermostat[ctr_output].time_pi_cycle * 60);
|
||||
|
@ -651,13 +650,13 @@ void ThermostatCalculatePI(uint8_t ctr_output)
|
|||
}
|
||||
|
||||
// Minimum action limiter
|
||||
// If result is less than the minimum action time, adjust to minimum value]]
|
||||
// If result is less than the minimum action time, adjust to minimum value
|
||||
if ((Thermostat[ctr_output].time_total_pi <= abs(((uint32_t)Thermostat[ctr_output].time_min_action * 60)))
|
||||
&& (Thermostat[ctr_output].time_total_pi != 0)) {
|
||||
Thermostat[ctr_output].time_total_pi = ((int32_t)Thermostat[ctr_output].time_min_action * 60);
|
||||
}
|
||||
// Maximum action limiter
|
||||
// If result is more than the maximum action time, adjust to maximum value]]
|
||||
// If result is more than the maximum action time, adjust to maximum value
|
||||
else if (Thermostat[ctr_output].time_total_pi > abs(((int32_t)Thermostat[ctr_output].time_max_action * 60))) {
|
||||
Thermostat[ctr_output].time_total_pi = ((int32_t)Thermostat[ctr_output].time_max_action * 60);
|
||||
}
|
||||
|
@ -747,7 +746,7 @@ void ThermostatWorkAutomaticRampUp(uint8_t ctr_output)
|
|||
}
|
||||
// Calculate absolute gradient since start of ramp-up (considering deadtime) in thousandths of º/hour
|
||||
Thermostat[ctr_output].temp_rampup_meas_gradient = (int32_t)((360000 * (int32_t)temp_delta_rampup) / (int32_t)time_in_rampup);
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + (uint32_t)Thermostat[ctr_output].time_rampup_cycle;
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + ((uint32_t)Thermostat[ctr_output].time_rampup_cycle * 60);
|
||||
// Set auxiliary variables
|
||||
Thermostat[ctr_output].temp_rampup_cycle = Thermostat[ctr_output].temp_measured;
|
||||
Thermostat[ctr_output].time_ctr_changepoint = uptime + (60 * (uint32_t)Thermostat[ctr_output].time_rampup_max);
|
||||
|
@ -758,7 +757,7 @@ void ThermostatWorkAutomaticRampUp(uint8_t ctr_output)
|
|||
// Calculate temp. gradient in º/hour and set again time_rampup_nextcycle and temp_rampup_cycle
|
||||
// temp_rampup_meas_gradient = ((3600 * temp_delta_rampup) / (os.time() - time_rampup_nextcycle))
|
||||
temp_delta_rampup = Thermostat[ctr_output].temp_measured - Thermostat[ctr_output].temp_rampup_cycle;
|
||||
uint32_t time_total_rampup = (uint32_t)Thermostat[ctr_output].time_rampup_cycle * Thermostat[ctr_output].counter_rampup_cycles;
|
||||
uint32_t time_total_rampup = (uint32_t)Thermostat[ctr_output].time_rampup_cycle * 60 * Thermostat[ctr_output].counter_rampup_cycles;
|
||||
// Translate into gradient per hour (thousandths of ° per hour)
|
||||
Thermostat[ctr_output].temp_rampup_meas_gradient = int32_t((360000 * (int32_t)temp_delta_rampup) / (int32_t)time_total_rampup);
|
||||
if ( ((Thermostat[ctr_output].temp_rampup_meas_gradient > 0)
|
||||
|
@ -776,7 +775,7 @@ void ThermostatWorkAutomaticRampUp(uint8_t ctr_output)
|
|||
// y = (((y2-y1)/(x2-x1))*(x-x1)) + y1
|
||||
Thermostat[ctr_output].temp_rampup_output_off = (int16_t)(((int32_t)temp_delta_rampup * (int32_t)(Thermostat[ctr_output].time_ctr_changepoint - (uptime - (time_total_rampup)))) / (int32_t)(time_total_rampup * Thermostat[ctr_output].counter_rampup_cycles)) + Thermostat[ctr_output].temp_rampup_cycle;
|
||||
// Set auxiliary variables
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + (uint32_t)Thermostat[ctr_output].time_rampup_cycle;
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + ((uint32_t)Thermostat[ctr_output].time_rampup_cycle * 60);
|
||||
Thermostat[ctr_output].temp_rampup_cycle = Thermostat[ctr_output].temp_measured;
|
||||
// Reset period counter
|
||||
Thermostat[ctr_output].counter_rampup_cycles = 1;
|
||||
|
@ -785,7 +784,7 @@ void ThermostatWorkAutomaticRampUp(uint8_t ctr_output)
|
|||
// Increase the period counter
|
||||
Thermostat[ctr_output].counter_rampup_cycles++;
|
||||
// Set another period
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + (uint32_t)Thermostat[ctr_output].time_rampup_cycle;
|
||||
Thermostat[ctr_output].time_rampup_nextcycle = uptime + ((uint32_t)Thermostat[ctr_output].time_rampup_cycle * 60);
|
||||
// Reset time_ctr_changepoint and temp_rampup_output_off
|
||||
Thermostat[ctr_output].time_ctr_changepoint = uptime + (60 * (uint32_t)Thermostat[ctr_output].time_rampup_max) - time_in_rampup;
|
||||
Thermostat[ctr_output].temp_rampup_output_off = Thermostat[ctr_output].temp_target_level_ctr;
|
||||
|
@ -1256,7 +1255,7 @@ void CmndTempMeasuredGrdRead(void)
|
|||
else {
|
||||
value = Thermostat[ctr_output].temp_measured_gradient;
|
||||
}
|
||||
ResponseCmndFloat((float)value / 10, 1);
|
||||
ResponseCmndFloat(((float)value) / 1000, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1280,25 +1279,11 @@ void CmndTimeManualToAutoSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_manual_to_auto = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_manual_to_auto = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_manual_to_auto * 60));
|
||||
}
|
||||
}
|
||||
|
||||
void CmndTimeOnLimitSet(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_on_limit = (uint16_t)(value / 60);
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_on_limit * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_manual_to_auto));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1330,17 +1315,33 @@ void CmndTimeResetSet(void)
|
|||
}
|
||||
}
|
||||
|
||||
void CmndTimePiProportRead(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
ResponseCmndNumber((int)Thermostat[ctr_output].time_proportional_pi);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndTimePiIntegrRead(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
ResponseCmndNumber((int)Thermostat[ctr_output].time_integral_pi);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndTimePiCycleSet(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_pi_cycle = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_pi_cycle = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_pi_cycle * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_pi_cycle));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1404,11 +1405,11 @@ void CmndTimeMaxActionSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_max_action = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_max_action = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_max_action * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_max_action));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1418,11 +1419,11 @@ void CmndTimeMinActionSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_min_action = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_min_action = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_min_action * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_min_action));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1432,11 +1433,11 @@ void CmndTimeSensLostSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_sens_lost = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_sens_lost = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_sens_lost * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_sens_lost));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1446,11 +1447,11 @@ void CmndTimeMinTurnoffActionSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_min_turnoff_action = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_min_turnoff_action = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_min_turnoff_action * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_min_turnoff_action));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1514,11 +1515,11 @@ void CmndTimeRampupMaxSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 86400)) {
|
||||
Thermostat[ctr_output].time_rampup_max = (uint16_t)(value / 60);
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_rampup_max = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
ResponseCmndNumber((int)(((uint32_t)Thermostat[ctr_output].time_rampup_max) * 60));
|
||||
ResponseCmndNumber((int)((uint32_t)Thermostat[ctr_output].time_rampup_max));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1528,7 +1529,7 @@ void CmndTimeRampupCycleSet(void)
|
|||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
uint32_t value = (uint32_t)(XdrvMailbox.payload);
|
||||
if ((value >= 0) && (value <= 54000)) {
|
||||
if ((value >= 0) && (value <= 1440)) {
|
||||
Thermostat[ctr_output].time_rampup_cycle = (uint16_t)value;
|
||||
}
|
||||
}
|
||||
|
@ -1563,22 +1564,6 @@ void CmndTempRampupPiAccErrSet(void)
|
|||
}
|
||||
}
|
||||
|
||||
void CmndTimePiProportRead(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
ResponseCmndNumber((int)Thermostat[ctr_output].time_proportional_pi);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndTimePiIntegrRead(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
uint8_t ctr_output = XdrvMailbox.index - 1;
|
||||
ResponseCmndNumber((int)Thermostat[ctr_output].time_integral_pi);
|
||||
}
|
||||
}
|
||||
|
||||
void CmndDiagnosticModeSet(void)
|
||||
{
|
||||
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= THERMOSTAT_CONTROLLER_OUTPUTS)) {
|
||||
|
|
|
@ -354,8 +354,8 @@ uint32_t wc_get_jpeg(uint8_t **buff) {
|
|||
_jpg_buf_len = wc_fb->len;
|
||||
_jpg_buf = wc_fb->buf;
|
||||
}
|
||||
esp_camera_fb_return(wc_fb);
|
||||
*buff = _jpg_buf;
|
||||
esp_camera_fb_return(wc_fb); // This frees the buffer
|
||||
*buff = _jpg_buf; // Buffer has been freed so this will cause exceptions
|
||||
return _jpg_buf_len;
|
||||
}
|
||||
|
||||
|
@ -447,7 +447,7 @@ void HandleImage(void) {
|
|||
len = wc_get_jpeg(&buff);
|
||||
if (len) {
|
||||
client.write(buff,len);
|
||||
free(buff);
|
||||
free(buff); // Buffer has been freed already in wc_get_jpeg so this will cause exceptions
|
||||
}
|
||||
} else {
|
||||
bnum--;
|
||||
|
@ -475,6 +475,50 @@ void handleMjpeg(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void HandleImageTheo(void) {
|
||||
if (!HttpCheckPriviledgedAccess(true)) { return; }
|
||||
|
||||
AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_HTTP "Capture image"));
|
||||
|
||||
if (Settings.webcam_config.stream) {
|
||||
if (!CamServer) {
|
||||
WcStreamControl();
|
||||
}
|
||||
}
|
||||
|
||||
camera_fb_t *wc_fb;
|
||||
wc_fb = esp_camera_fb_get(); // Acquire frame
|
||||
if (!wc_fb) {
|
||||
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Frame buffer could not be acquired"));
|
||||
return;
|
||||
}
|
||||
|
||||
size_t _jpg_buf_len = 0;
|
||||
uint8_t * _jpg_buf = NULL;
|
||||
if (wc_fb->format != PIXFORMAT_JPEG) {
|
||||
bool jpeg_converted = frame2jpg(wc_fb, 80, &_jpg_buf, &_jpg_buf_len);
|
||||
if (!jpeg_converted) {
|
||||
_jpg_buf_len = wc_fb->len;
|
||||
_jpg_buf = wc_fb->buf;
|
||||
}
|
||||
} else {
|
||||
_jpg_buf_len = wc_fb->len;
|
||||
_jpg_buf = wc_fb->buf;
|
||||
}
|
||||
|
||||
if (_jpg_buf_len) {
|
||||
Webserver->client().flush();
|
||||
WSHeaderSend();
|
||||
Webserver->sendHeader(F("Content-disposition"), F("inline; filename=cap.jpg"));
|
||||
Webserver->send_P(200, "image/jpeg", (char *)_jpg_buf, _jpg_buf_len);
|
||||
Webserver->client().stop();
|
||||
}
|
||||
|
||||
esp_camera_fb_return(wc_fb); // Free frame buffer
|
||||
|
||||
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Image sent"));
|
||||
}
|
||||
|
||||
#ifdef USE_FACE_DETECT
|
||||
|
||||
static mtmn_config_t mtmn_config = {0};
|
||||
|
@ -812,6 +856,8 @@ void wc_loop(void) {
|
|||
void wc_pic_setup(void) {
|
||||
Webserver->on("/wc.jpg", HandleImage);
|
||||
Webserver->on("/wc.mjpeg", HandleImage);
|
||||
|
||||
Webserver->on("/snapshot.jpg", HandleImageTheo);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -59,13 +59,14 @@
|
|||
#define D_CMND_I2CREAD "I2CRead"
|
||||
#define D_CMND_I2CSTRETCH "I2CStretch"
|
||||
#define D_CMND_I2CCLOCK "I2CClock"
|
||||
#define D_CMND_SERBUFF "SerBufSize"
|
||||
|
||||
const char kDebugCommands[] PROGMEM = "|" // No prefix
|
||||
D_CMND_CFGDUMP "|" D_CMND_CFGPEEK "|" D_CMND_CFGPOKE "|"
|
||||
#ifdef USE_WEBSERVER
|
||||
D_CMND_CFGXOR "|"
|
||||
#endif
|
||||
D_CMND_CPUCHECK "|"
|
||||
D_CMND_CPUCHECK "|" D_CMND_SERBUFF "|"
|
||||
#ifdef DEBUG_THEO
|
||||
D_CMND_EXCEPTION "|"
|
||||
#endif
|
||||
|
@ -80,7 +81,7 @@ void (* const DebugCommand[])(void) PROGMEM = {
|
|||
#ifdef USE_WEBSERVER
|
||||
&CmndCfgXor,
|
||||
#endif
|
||||
&CmndCpuCheck,
|
||||
&CmndCpuCheck, &CmndSerBufSize,
|
||||
#ifdef DEBUG_THEO
|
||||
&CmndException,
|
||||
#endif
|
||||
|
@ -479,6 +480,18 @@ void CmndCpuCheck(void)
|
|||
ResponseCmndNumber(CPU_load_check);
|
||||
}
|
||||
|
||||
void CmndSerBufSize(void)
|
||||
{
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
Serial.setRxBufferSize(XdrvMailbox.payload);
|
||||
}
|
||||
#ifdef ESP8266
|
||||
ResponseCmndNumber(Serial.getRxBufferSize());
|
||||
#else
|
||||
ResponseCmndDone();
|
||||
#endif
|
||||
}
|
||||
|
||||
void CmndFreemem(void)
|
||||
{
|
||||
if (XdrvMailbox.data_len > 0) {
|
||||
|
|
Loading…
Reference in New Issue