4.0.7 20170319
* Increased Sonoff Led PWM frequency from 432 to 1000
* Fix possible watch dog reboot after changing module type on web page
* Fix reporting of GPIO usage from web page
* Fix Sonoff Led blank during firmware upgrade
* Fix Sonoff Led flicker and possible flash corruption by using latest
Arduino-esp8266 versions
*   of pwm core files included in sonoff library (#211)
* Add PWM output control with commands PWM1 to PWM5 using user
selectable GPIOs (#211)
* Fix exceptions due to low values of commands HlwPCal (10000), HlwUCal
(1000) and HlwICal (2500) (#223)
* Add Switch state to sensor status (#227, #233)
* Add user configuarble GPIO to module Sonoff Touch (#228)
* Add define WEB_PORT to user_config.h to change default web server port
from 80 (#232)
* Fix failed Ota Firmware upgrade started from Web page (#235)
This commit is contained in:
arendst 2017-03-19 18:19:08 +01:00
parent c4cdd4459c
commit 742a87df8a
16 changed files with 637 additions and 49 deletions

View File

@ -1,7 +1,7 @@
## Sonoff-Tasmota ## Sonoff-Tasmota
Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE. Provide ESP8266 based Sonoff by [iTead Studio](https://www.itead.cc/) and ElectroDragon IoT Relay with Serial, Web and MQTT control allowing 'Over the Air' or OTA firmware updates using Arduino IDE.
Current version is **4.0.6** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information. Current version is **4.0.7** - See [sonoff/_releasenotes.ino](https://github.com/arendst/Sonoff-Tasmota/blob/master/sonoff/_releasenotes.ino) for change information.
- This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic. - This version provides all (Sonoff) modules in one file and starts up with Sonoff Basic.
- Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```. - Once uploaded select module using the configuration webpage or the commands ```Modules``` and ```Module```.

Binary file not shown.

Binary file not shown.

View File

@ -1,4 +1,18 @@
/* 4.0.6 20170316 /* 4.0.7 20170319
* Increased Sonoff Led PWM frequency from 432 to 1000
* Fix possible watch dog reboot after changing module type on web page
* Fix reporting of GPIO usage from web page
* Fix Sonoff Led blank during firmware upgrade
* Fix Sonoff Led flicker and possible flash corruption by using latest Arduino-esp8266 versions
* of pwm core files included in sonoff library (#211)
* Add PWM output control with commands PWM1 to PWM5 using user selectable GPIOs (#211)
* Fix exceptions due to low values of commands HlwPCal (10000), HlwUCal (1000) and HlwICal (2500) (#223)
* Add Switch state to sensor status (#227, #233)
* Add user configuarble GPIO to module Sonoff Touch (#228)
* Add define WEB_PORT to user_config.h to change default web server port from 80 (#232)
* Fix failed Ota Firmware upgrade started from Web page (#235)
*
* 4.0.6 20170316
* Fix to better find device by Wifi hostname * Fix to better find device by Wifi hostname
* Fix compile error when some I2C devices are disabled * Fix compile error when some I2C devices are disabled
* Add (experimental) support for SHT1X emulating I2C (#97) * Add (experimental) support for SHT1X emulating I2C (#97)

103
sonoff/core_esp8266_timer.c Normal file
View File

@ -0,0 +1,103 @@
/*
timer.c - Timer1 library for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 "wiring_private.h"
#include "pins_arduino.h"
#include "c_types.h"
#include "ets_sys.h"
// ------------------------------------------------------------------ -
// timer 1
static volatile timercallback timer1_user_cb = NULL;
void ICACHE_RAM_ATTR timer1_isr_handler(void *para){
(void) para;
if ((T1C & ((1 << TCAR) | (1 << TCIT))) == 0) TEIE &= ~TEIE1;//edge int disable
T1I = 0;
if (timer1_user_cb) {
// to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts
timer1_user_cb();
xt_wsr_ps(savedPS);
}
}
void ICACHE_RAM_ATTR timer1_isr_init(){
ETS_FRC_TIMER1_INTR_ATTACH(timer1_isr_handler, NULL);
}
void timer1_attachInterrupt(timercallback userFunc) {
timer1_user_cb = userFunc;
ETS_FRC1_INTR_ENABLE();
}
void ICACHE_RAM_ATTR timer1_detachInterrupt() {
timer1_user_cb = 0;
TEIE &= ~TEIE1;//edge int disable
ETS_FRC1_INTR_DISABLE();
}
void timer1_enable(uint8_t divider, uint8_t int_type, uint8_t reload){
T1C = (1 << TCTE) | ((divider & 3) << TCPD) | ((int_type & 1) << TCIT) | ((reload & 1) << TCAR);
T1I = 0;
}
void ICACHE_RAM_ATTR timer1_write(uint32_t ticks){
T1L = ((ticks)& 0x7FFFFF);
if ((T1C & (1 << TCIT)) == 0) TEIE |= TEIE1;//edge int enable
}
void ICACHE_RAM_ATTR timer1_disable(){
T1C = 0;
T1I = 0;
}
//-------------------------------------------------------------------
// timer 0
static volatile timercallback timer0_user_cb = NULL;
void ICACHE_RAM_ATTR timer0_isr_handler(void* para){
(void) para;
if (timer0_user_cb) {
// to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts
timer0_user_cb();
xt_wsr_ps(savedPS);
}
}
void timer0_isr_init(){
ETS_CCOMPARE0_INTR_ATTACH(timer0_isr_handler, NULL);
}
void timer0_attachInterrupt(timercallback userFunc) {
timer0_user_cb = userFunc;
ETS_CCOMPARE0_ENABLE();
}
void ICACHE_RAM_ATTR timer0_detachInterrupt() {
timer0_user_cb = NULL;
ETS_CCOMPARE0_DISABLE();
}

View File

@ -0,0 +1,188 @@
/*
digital.c - wiring digital implementation for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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
*/
#define ARDUINO_MAIN
#include "wiring_private.h"
#include "pins_arduino.h"
#include "c_types.h"
#include "eagle_soc.h"
#include "ets_sys.h"
extern void pwm_stop_pin(uint8_t pin);
uint8_t esp8266_gpioToFn[16] = {0x34, 0x18, 0x38, 0x14, 0x3C, 0x40, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x30, 0x04, 0x08, 0x0C, 0x10};
extern void __pinMode(uint8_t pin, uint8_t mode) {
pwm_stop_pin(pin);
if(pin < 16){
if(mode == SPECIAL){
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
GPEC = (1 << pin); //Disable
GPF(pin) = GPFFS(GPFFS_BUS(pin));//Set mode to BUS (RX0, TX0, TX1, SPI, HSPI or CLK depending in the pin)
if(pin == 3) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
} else if(mode & FUNCTION_0){
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
GPEC = (1 << pin); //Disable
GPF(pin) = GPFFS((mode >> 4) & 0x07);
if(pin == 13 && mode == FUNCTION_4) GPF(pin) |= (1 << GPFPU);//enable pullup on RX
} else if(mode == OUTPUT || mode == OUTPUT_OPEN_DRAIN){
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPC(pin) = (GPC(pin) & (0xF << GPCI)); //SOURCE(GPIO) | DRIVER(NORMAL) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
if(mode == OUTPUT_OPEN_DRAIN) GPC(pin) |= (1 << GPCD);
GPES = (1 << pin); //Enable
} else if(mode == INPUT || mode == INPUT_PULLUP){
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPEC = (1 << pin); //Disable
GPC(pin) = (GPC(pin) & (0xF << GPCI)) | (1 << GPCD); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(UNCHANGED) | WAKEUP_ENABLE(DISABLED)
if(mode == INPUT_PULLUP) {
GPF(pin) |= (1 << GPFPU); // Enable Pullup
}
} else if(mode == WAKEUP_PULLUP || mode == WAKEUP_PULLDOWN){
GPF(pin) = GPFFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPEC = (1 << pin); //Disable
if(mode == WAKEUP_PULLUP) {
GPF(pin) |= (1 << GPFPU); // Enable Pullup
GPC(pin) = (1 << GPCD) | (4 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(LOW) | WAKEUP_ENABLE(ENABLED)
} else {
GPF(pin) |= (1 << GPFPD); // Enable Pulldown
GPC(pin) = (1 << GPCD) | (5 << GPCI) | (1 << GPCWE); //SOURCE(GPIO) | DRIVER(OPEN_DRAIN) | INT_TYPE(HIGH) | WAKEUP_ENABLE(ENABLED)
}
}
} else if(pin == 16){
GPF16 = GP16FFS(GPFFS_GPIO(pin));//Set mode to GPIO
GPC16 = 0;
if(mode == INPUT || mode == INPUT_PULLDOWN_16){
if(mode == INPUT_PULLDOWN_16){
GPF16 |= (1 << GP16FPD);//Enable Pulldown
}
GP16E &= ~1;
} else if(mode == OUTPUT){
GP16E |= 1;
}
}
}
extern void ICACHE_RAM_ATTR __digitalWrite(uint8_t pin, uint8_t val) {
pwm_stop_pin(pin);
if(pin < 16){
if(val) GPOS = (1 << pin);
else GPOC = (1 << pin);
} else if(pin == 16){
if(val) GP16O |= 1;
else GP16O &= ~1;
}
}
extern int ICACHE_RAM_ATTR __digitalRead(uint8_t pin) {
pwm_stop_pin(pin);
if(pin < 16){
return GPIP(pin);
} else if(pin == 16){
return GP16I & 0x01;
}
return 0;
}
/*
GPIO INTERRUPTS
*/
typedef void (*voidFuncPtr)(void);
typedef struct {
uint8_t mode;
void (*fn)(void);
} interrupt_handler_t;
static interrupt_handler_t interrupt_handlers[16];
static uint32_t interrupt_reg = 0;
void ICACHE_RAM_ATTR interrupt_handler(void *arg) {
(void) arg;
uint32_t status = GPIE;
GPIEC = status;//clear them interrupts
uint32_t levels = GPI;
if(status == 0 || interrupt_reg == 0) return;
ETS_GPIO_INTR_DISABLE();
int i = 0;
uint32_t changedbits = status & interrupt_reg;
while(changedbits){
while(!(changedbits & (1 << i))) i++;
changedbits &= ~(1 << i);
interrupt_handler_t *handler = &interrupt_handlers[i];
if (handler->fn &&
(handler->mode == CHANGE ||
(handler->mode & 1) == !!(levels & (1 << i)))) {
// to make ISR compatible to Arduino AVR model where interrupts are disabled
// we disable them before we call the client ISR
uint32_t savedPS = xt_rsil(15); // stop other interrupts
handler->fn();
xt_wsr_ps(savedPS);
}
}
ETS_GPIO_INTR_ENABLE();
}
extern void ICACHE_RAM_ATTR __attachInterrupt(uint8_t pin, voidFuncPtr userFunc, int mode) {
if(pin < 16) {
interrupt_handler_t *handler = &interrupt_handlers[pin];
handler->mode = mode;
handler->fn = userFunc;
interrupt_reg |= (1 << pin);
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
GPIEC = (1 << pin); //Clear Interrupt for this pin
GPC(pin) |= ((mode & 0xF) << GPCI);//INT mode "mode"
}
}
extern void ICACHE_RAM_ATTR __detachInterrupt(uint8_t pin) {
if(pin < 16) {
GPC(pin) &= ~(0xF << GPCI);//INT mode disabled
GPIEC = (1 << pin); //Clear Interrupt for this pin
interrupt_reg &= ~(1 << pin);
interrupt_handler_t *handler = &interrupt_handlers[pin];
handler->mode = 0;
handler->fn = 0;
}
}
void initPins() {
//Disable UART interrupts
system_set_os_print(0);
U0IE = 0;
U1IE = 0;
for (int i = 0; i <= 5; ++i) {
pinMode(i, INPUT);
}
// pins 6-11 are used for the SPI flash interface
for (int i = 12; i <= 16; ++i) {
pinMode(i, INPUT);
}
ETS_GPIO_INTR_ATTACH(interrupt_handler, &interrupt_reg);
ETS_GPIO_INTR_ENABLE();
}
extern void pinMode(uint8_t pin, uint8_t mode) __attribute__ ((weak, alias("__pinMode")));
extern void digitalWrite(uint8_t pin, uint8_t val) __attribute__ ((weak, alias("__digitalWrite")));
extern int digitalRead(uint8_t pin) __attribute__ ((weak, alias("__digitalRead")));
extern void attachInterrupt(uint8_t pin, voidFuncPtr handler, int mode) __attribute__ ((weak, alias("__attachInterrupt")));
extern void detachInterrupt(uint8_t pin) __attribute__ ((weak, alias("__detachInterrupt")));

View File

@ -0,0 +1,221 @@
/*
pwm.c - analogWrite implementation for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the esp8266 core for Arduino environment.
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 "wiring_private.h"
#include "pins_arduino.h"
#include "c_types.h"
#include "eagle_soc.h"
#include "ets_sys.h"
#ifndef F_CPU
#define F_CPU 800000000L
#endif
struct pwm_isr_table {
uint8_t len;
uint16_t steps[17];
uint32_t masks[17];
};
struct pwm_isr_data {
struct pwm_isr_table tables[2];
uint8_t active;//0 or 1, which table is active in ISR
};
static struct pwm_isr_data _pwm_isr_data;
uint32_t pwm_mask = 0;
uint16_t pwm_values[17] = {0,};
uint32_t pwm_freq = 1000;
uint32_t pwm_range = PWMRANGE;
uint8_t pwm_steps_changed = 0;
uint32_t pwm_multiplier = 0;
int pwm_sort_array(uint16_t a[], uint16_t al)
{
uint16_t i, j;
for (i = 1; i < al; i++) {
uint16_t tmp = a[i];
for (j = i; j >= 1 && tmp < a[j-1]; j--) {
a[j] = a[j-1];
}
a[j] = tmp;
}
int bl = 1;
for(i = 1; i < al; i++) {
if(a[i] != a[i-1]) {
a[bl++] = a[i];
}
}
return bl;
}
uint32_t pwm_get_mask(uint16_t value)
{
uint32_t mask = 0;
int i;
for(i=0; i<17; i++) {
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] == value) {
mask |= (1 << i);
}
}
return mask;
}
void prep_pwm_steps()
{
if(pwm_mask == 0) {
return;
}
int pwm_temp_steps_len = 0;
uint16_t pwm_temp_steps[17];
uint32_t pwm_temp_masks[17];
uint32_t range = pwm_range;
if((F_CPU / ESP8266_CLOCK) == 1) {
range /= 2;
}
int i;
for(i=0; i<17; i++) {
if((pwm_mask & (1 << i)) != 0 && pwm_values[i] != 0) {
pwm_temp_steps[pwm_temp_steps_len++] = pwm_values[i];
}
}
pwm_temp_steps[pwm_temp_steps_len++] = range;
pwm_temp_steps_len = pwm_sort_array(pwm_temp_steps, pwm_temp_steps_len) - 1;
for(i=0; i<pwm_temp_steps_len; i++) {
pwm_temp_masks[i] = pwm_get_mask(pwm_temp_steps[i]);
}
for(i=pwm_temp_steps_len; i>0; i--) {
pwm_temp_steps[i] = pwm_temp_steps[i] - pwm_temp_steps[i-1];
}
pwm_steps_changed = 0;
struct pwm_isr_table *table = &(_pwm_isr_data.tables[!_pwm_isr_data.active]);
table->len = pwm_temp_steps_len;
ets_memcpy(table->steps, pwm_temp_steps, (pwm_temp_steps_len + 1) * 2);
ets_memcpy(table->masks, pwm_temp_masks, pwm_temp_steps_len * 4);
pwm_multiplier = ESP8266_CLOCK/(range * pwm_freq);
pwm_steps_changed = 1;
}
void ICACHE_RAM_ATTR pwm_timer_isr() //103-138
{
struct pwm_isr_table *table = &(_pwm_isr_data.tables[_pwm_isr_data.active]);
static uint8_t current_step = 0;
TEIE &= ~TEIE1;//14
T1I = 0;//9
if(current_step < table->len) { //20/21
uint32_t mask = table->masks[current_step] & pwm_mask;
if(mask & 0xFFFF) {
GPOC = mask & 0xFFFF; //15/21
}
if(mask & 0x10000) {
GP16O = 0; //6/13
}
current_step++;//1
} else {
current_step = 0;//1
if(pwm_mask == 0) { //12
table->len = 0;
return;
}
if(pwm_mask & 0xFFFF) {
GPOS = pwm_mask & 0xFFFF; //11
}
if(pwm_mask & 0x10000) {
GP16O = 1; //5/13
}
if(pwm_steps_changed) { //12/21
_pwm_isr_data.active = !_pwm_isr_data.active;
table = &(_pwm_isr_data.tables[_pwm_isr_data.active]);
pwm_steps_changed = 0;
}
}
T1L = (table->steps[current_step] * pwm_multiplier);//23
TEIE |= TEIE1;//13
}
void pwm_start_timer()
{
timer1_disable();
ETS_FRC_TIMER1_INTR_ATTACH(NULL, NULL);
ETS_FRC_TIMER1_NMI_INTR_ATTACH(pwm_timer_isr);
timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
timer1_write(1);
}
void ICACHE_RAM_ATTR pwm_stop_pin(uint8_t pin)
{
if(pwm_mask){
pwm_mask &= ~(1 << pin);
if(pwm_mask == 0) {
ETS_FRC_TIMER1_NMI_INTR_ATTACH(NULL);
timer1_disable();
timer1_isr_init();
}
}
}
extern void __analogWrite(uint8_t pin, int value)
{
bool start_timer = false;
if(value == 0) {
digitalWrite(pin, LOW);
prep_pwm_steps();
return;
}
if((pwm_mask & (1 << pin)) == 0) {
if(pwm_mask == 0) {
memset(&_pwm_isr_data, 0, sizeof(_pwm_isr_data));
start_timer = true;
}
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
pwm_mask |= (1 << pin);
}
if((F_CPU / ESP8266_CLOCK) == 1) {
value = (value+1) / 2;
}
pwm_values[pin] = value % (pwm_range + 1);
prep_pwm_steps();
if(start_timer) {
pwm_start_timer();
}
}
extern void __analogWriteFreq(uint32_t freq)
{
pwm_freq = freq;
prep_pwm_steps();
}
extern void __analogWriteRange(uint32_t range)
{
pwm_range = range;
prep_pwm_steps();
}
extern void analogWrite(uint8_t pin, int val) __attribute__ ((weak, alias("__analogWrite")));
extern void analogWriteFreq(uint32_t freq) __attribute__ ((weak, alias("__analogWriteFreq")));
extern void analogWriteRange(uint32_t range) __attribute__ ((weak, alias("__analogWriteRange")));

View File

@ -191,6 +191,7 @@ struct SYSCFG {
char ntp_server[3][33]; char ntp_server[3][33];
uint16_t pulsetime[MAX_PULSETIMERS]; uint16_t pulsetime[MAX_PULSETIMERS];
uint16_t pwmvalue[5];
} sysCfg; } sysCfg;

View File

@ -198,7 +198,8 @@ void CFG_Save()
} }
} else { } else {
#endif // USE_SPIFFS #endif // USE_SPIFFS
if (sysCfg.module != SONOFF_LED) noInterrupts(); noInterrupts();
// if (sysCfg.module != SONOFF_LED) noInterrupts();
if (sysCfg.saveFlag == 0) { // Handle default and rollover if (sysCfg.saveFlag == 0) { // Handle default and rollover
spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1));
spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
@ -206,7 +207,8 @@ void CFG_Save()
sysCfg.saveFlag++; sysCfg.saveFlag++;
spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1)); spi_flash_erase_sector(CFG_LOCATION + (sysCfg.saveFlag &1));
spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG)); spi_flash_write((CFG_LOCATION + (sysCfg.saveFlag &1)) * SPI_FLASH_SEC_SIZE, (uint32*)&sysCfg, sizeof(SYSCFG));
if (sysCfg.module != SONOFF_LED) interrupts(); interrupts();
// if (sysCfg.module != SONOFF_LED) interrupts();
snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to flash at %X and count %d"), sizeof(SYSCFG), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag); snprintf_P(log, sizeof(log), PSTR("Config: Saved configuration (%d bytes) to flash at %X and count %d"), sizeof(SYSCFG), CFG_LOCATION + (sysCfg.saveFlag &1), sysCfg.saveFlag);
addLog(LOG_LEVEL_DEBUG, log); addLog(LOG_LEVEL_DEBUG, log);
} }
@ -511,6 +513,9 @@ void CFG_DefaultSet2()
CFG_DefaultSet_4_0_4(); CFG_DefaultSet_4_0_4();
sysCfg.pulsetime[0] = APP_PULSETIME; sysCfg.pulsetime[0] = APP_PULSETIME;
// v4.0.7
for (byte i = 0; i < 5; i++) sysCfg.pwmvalue[i] = 0;
} }
void CFG_DefaultSet_3_2_4() void CFG_DefaultSet_3_2_4()
@ -738,6 +743,9 @@ void CFG_Delta()
memmove(sysCfg.my_module.gp.io, sysCfg.my_module.gp.io +1, MAX_GPIO_PIN -1); // move myio 1 byte to front memmove(sysCfg.my_module.gp.io, sysCfg.my_module.gp.io +1, MAX_GPIO_PIN -1); // move myio 1 byte to front
sysCfg.my_module.gp.io[MAX_GPIO_PIN -1] = 0; // Clear ADC0 sysCfg.my_module.gp.io[MAX_GPIO_PIN -1] = 0; // Clear ADC0
} }
if (sysCfg.version < 0x04000700) {
for (byte i = 0; i < 5; i++) sysCfg.pwmvalue[i] = 0;
}
sysCfg.version = VERSION; sysCfg.version = VERSION;
} }
} }

View File

@ -12,9 +12,9 @@
//#define ALLOW_MIGRATE_TO_V3 //#define ALLOW_MIGRATE_TO_V3
#ifdef ALLOW_MIGRATE_TO_V3 #ifdef ALLOW_MIGRATE_TO_V3
#define VERSION 0x03091D00 // 3.9.29 #define VERSION 0x03091E00 // 3.9.30
#else #else
#define VERSION 0x04000600 // 4.0.6 #define VERSION 0x04000700 // 4.0.7
#endif // ALLOW_MIGRATE_TO_V3 #endif // ALLOW_MIGRATE_TO_V3
enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL}; enum log_t {LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE, LOG_LEVEL_ALL};
@ -115,6 +115,9 @@ enum emul_t {EMUL_NONE, EMUL_WEMO, EMUL_HUE, EMUL_MAX};
#define MAX_PULSETIMERS 4 // Max number of supported pulse timers #define MAX_PULSETIMERS 4 // Max number of supported pulse timers
#define WS2812_MAX_LEDS 256 // Max number of LEDs #define WS2812_MAX_LEDS 256 // Max number of LEDs
#define PWM_RANGE 1023 // 127..1023 but as Color is addressed by 8 bits it should be 255 for my code
#define PWM_FREQ 1000 // 100..1000 Hz led refresh
#define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power (Pow) #define MAX_POWER_HOLD 10 // Time in SECONDS to allow max agreed power (Pow)
#define MAX_POWER_WINDOW 30 // Time in SECONDS to disable allow max agreed power (Pow) #define MAX_POWER_WINDOW 30 // Time in SECONDS to disable allow max agreed power (Pow)
#define SAFE_POWER_HOLD 10 // Time in SECONDS to allow max unit safe power (Pow) #define SAFE_POWER_HOLD 10 // Time in SECONDS to allow max unit safe power (Pow)
@ -284,6 +287,8 @@ uint8_t swt_flg = 0; // Any external switch configured
uint8_t dht_type = 0; // DHT type (DHT11, DHT21 or DHT22) uint8_t dht_type = 0; // DHT type (DHT11, DHT21 or DHT22)
uint8_t hlw_flg = 0; // Power monitor configured uint8_t hlw_flg = 0; // Power monitor configured
uint8_t i2c_flg = 0; // I2C configured uint8_t i2c_flg = 0; // I2C configured
uint8_t pwm_flg = 0; // PWM configured
uint8_t pwm_idxoffset = 0; // Allowed PWM command offset (change for Sonoff Led)
boolean mDNSbegun = false; boolean mDNSbegun = false;
@ -883,7 +888,10 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
} }
else if (!strcmp(type,"MODULE")) { else if (!strcmp(type,"MODULE")) {
if ((data_len > 0) && (payload > 0) && (payload <= MAXMODULE)) { if ((data_len > 0) && (payload > 0) && (payload <= MAXMODULE)) {
sysCfg.module = payload -1; payload--;
byte new_modflg = (sysCfg.module != payload);
sysCfg.module = payload;
if (new_modflg) for (byte i = 0; i < MAX_GPIO_PIN; i++) sysCfg.my_module.gp.io[i] = 0;
restartflag = 2; restartflag = 2;
} }
snprintf_P(stemp1, sizeof(stemp1), modules[sysCfg.module].name); snprintf_P(stemp1, sizeof(stemp1), modules[sysCfg.module].name);
@ -957,6 +965,21 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
} }
snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue); snprintf_P(svalue, sizeof(svalue), PSTR("%s\"}"), svalue);
} }
else if (!strcmp(type,"PWM") && (index > pwm_idxoffset) && (index <= 5)) {
if ((data_len > 0) && (payload >= 0) && (payload <= PWM_RANGE) && (pin[GPIO_PWM1 + index -1] < 99)) {
sysCfg.pwmvalue[index -1] = payload;
analogWrite(pin[GPIO_PWM1 + index -1], payload);
}
snprintf_P(svalue, sizeof(svalue), PSTR("{\"PWM\":{"));
bool first = true;
for (byte i = 0; i < 5; i++) {
if(pin[GPIO_PWM1 + i] < 99) {
snprintf_P(svalue, sizeof(svalue), PSTR("%s%s\"PWM%d\":%d"), svalue, first ? "" : ", ", i+1, sysCfg.pwmvalue[i]);
first = false;
}
}
snprintf_P(svalue, sizeof(svalue), PSTR("%s}}"),svalue);
}
else if (!strcmp(type,"SLEEP")) { else if (!strcmp(type,"SLEEP")) {
if ((data_len > 0) && (payload >= 0) && (payload < 251)) { if ((data_len > 0) && (payload >= 0) && (payload < 251)) {
if ((!sysCfg.sleep && payload) || (sysCfg.sleep && !payload)) restartflag = 2; if ((!sysCfg.sleep && payload) || (sysCfg.sleep && !payload)) restartflag = 2;
@ -1247,6 +1270,7 @@ void mqttDataCb(char* topic, byte* data, unsigned int data_len)
snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, WebPassword, Emulation"), svalue); snprintf_P(svalue, sizeof(svalue), PSTR("%s, Weblog, Webserver, WebPassword, Emulation"), svalue);
#endif #endif
if (swt_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, SwitchMode"), svalue); if (swt_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, SwitchMode"), svalue);
if (pwm_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, PWM"), svalue);
#ifdef USE_I2C #ifdef USE_I2C
if (i2c_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, I2CScan"), svalue); if (i2c_flg) snprintf_P(svalue, sizeof(svalue), PSTR("%s, I2CScan"), svalue);
#endif // USE_I2C #endif // USE_I2C
@ -1508,7 +1532,13 @@ void state_mqttPresent(char* svalue, uint16_t ssvalue)
void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson) void sensors_mqttPresent(char* svalue, uint16_t ssvalue, uint8_t* djson)
{ {
snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str()); snprintf_P(svalue, ssvalue, PSTR("%s{\"Time\":\"%s\""), svalue, getDateTime().c_str());
for (byte i = 0; i < 4; i++) {
if (pin[GPIO_SWT1 +i] < 99) {
byte swm = ((sysCfg.switchmode[i] == FOLLOW_INV)||(sysCfg.switchmode[i] == PUSHBUTTON_INV));
snprintf_P(svalue, ssvalue, PSTR("%s, \"Switch%d\":\"%s\""),
svalue, i +1, (lastwallswitch[i]) ? (swm) ? MQTT_STATUS_ON : MQTT_STATUS_OFF : (swm) ? MQTT_STATUS_OFF : MQTT_STATUS_ON);
}
}
#ifndef USE_ADC_VCC #ifndef USE_ADC_VCC
if (pin[GPIO_ADC0] < 99) { if (pin[GPIO_ADC0] < 99) {
snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0)); snprintf_P(svalue, ssvalue, PSTR("%s, \"AnalogInput0\":%d"), svalue, analogRead(A0));
@ -1999,6 +2029,9 @@ void GPIO_init()
} }
} }
analogWriteRange(PWM_RANGE); // Default is 1023 (Arduino.h)
analogWriteFreq(PWM_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c)
Maxdevice = 1; Maxdevice = 1;
if (sysCfg.module == SONOFF_DUAL) { if (sysCfg.module == SONOFF_DUAL) {
Maxdevice = 2; Maxdevice = 2;
@ -2009,6 +2042,7 @@ void GPIO_init()
Baudrate = 19200; Baudrate = 19200;
} }
else if (sysCfg.module == SONOFF_LED) { else if (sysCfg.module == SONOFF_LED) {
pwm_idxoffset = 2;
pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led pin[GPIO_WS2812] = 99; // I do not allow both Sonoff Led AND WS2812 led
sl_init(); sl_init();
} }
@ -2033,6 +2067,14 @@ void GPIO_init()
lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // set global now so doesn't change the saved power state on first switch check lastwallswitch[i] = digitalRead(pin[GPIO_SWT1 +i]); // set global now so doesn't change the saved power state on first switch check
} }
} }
for (byte i = pwm_idxoffset; i < 5; i++) {
if (pin[GPIO_PWM1 +i] < 99) {
pwm_flg = 1;
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
analogWrite(pin[GPIO_PWM1 +i], sysCfg.pwmvalue[i]);
}
}
if (sysCfg.module == EXS_RELAY) { if (sysCfg.module == EXS_RELAY) {
setLatchingRelay(0,2); setLatchingRelay(0,2);
setLatchingRelay(1,2); setLatchingRelay(1,2);

View File

@ -37,6 +37,11 @@ enum upins_t {
GPIO_LED2_INV, GPIO_LED2_INV,
GPIO_LED3_INV, GPIO_LED3_INV,
GPIO_LED4_INV, GPIO_LED4_INV,
GPIO_PWM1, // Sonoff Led Cold
GPIO_PWM2, // Sonoff Led Warm
GPIO_PWM3, // Red (swapped with Blue from original)
GPIO_PWM4, // Green
GPIO_PWM5, // Blue (swapped with Red from original)
GPIO_SENSOR_END }; GPIO_SENSOR_END };
// Text in webpage Module Parameters and commands GPIOS and GPIO // Text in webpage Module Parameters and commands GPIOS and GPIO
@ -73,17 +78,17 @@ const char sensors[GPIO_SENSOR_END][9] PROGMEM = {
"Led1I", "Led1I",
"Led2I", "Led2I",
"Led3I", "Led3I",
"Led4I" "Led4I",
"PWM1",
"PWM2",
"PWM3",
"PWM4",
"PWM5"
}; };
// Programmer selectable GPIO functionality offset by user selectable GPIOs // Programmer selectable GPIO functionality offset by user selectable GPIOs
enum fpins_t { enum fpins_t {
GPIO_PWM0 = GPIO_SENSOR_END, // Cold GPIO_RXD = GPIO_SENSOR_END, // Serial interface
GPIO_PWM1, // Warm
GPIO_PWM2, // Red (swapped with Blue from original)
GPIO_PWM3, // Green
GPIO_PWM4, // Blue (swapped with Red from original)
GPIO_RXD, // Serial interface
GPIO_TXD, // Serial interface GPIO_TXD, // Serial interface
GPIO_HLW_SEL, // HLW8012 Sel output (Sonoff Pow) GPIO_HLW_SEL, // HLW8012 Sel output (Sonoff Pow)
GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow) GPIO_HLW_CF1, // HLW8012 CF1 voltage / current (Sonoff Pow)
@ -250,7 +255,10 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
}, },
{ "Sonoff Touch", // Sonoff Touch (ESP8285) { "Sonoff Touch", // Sonoff Touch (ESP8285)
GPIO_KEY1, // GPIO00 Button GPIO_KEY1, // GPIO00 Button
0, 0, 0, 0, 0, GPIO_USER, // GPIO01 Serial RXD and Optional sensor
0,
GPIO_USER, // GPIO03 Serial TXD and Optional sensor
0, 0,
0, 0, 0, // Flash connection 0, 0, 0, // Flash connection
0, 0, 0, 0, 0, 0,
GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On) GPIO_REL1, // GPIO12 Red Led and Relay (0 = Off, 1 = On)
@ -263,9 +271,9 @@ const mytmplt modules[MAXMODULE] PROGMEM = {
GPIO_USER, // GPIO04 Optional sensor (PWM3 Green) GPIO_USER, // GPIO04 Optional sensor (PWM3 Green)
GPIO_USER, // GPIO05 Optional sensor (PWM2 Red) GPIO_USER, // GPIO05 Optional sensor (PWM2 Red)
0, 0, 0, 0, 0, 0, // Flash connection 0, 0, 0, 0, 0, 0, // Flash connection
GPIO_PWM0, // GPIO12 Cold light GPIO_PWM1, // GPIO12 Cold light (PWM0 Cold)
GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off) GPIO_LED1_INV, // GPIO13 Blue Led (0 = On, 1 = Off)
GPIO_PWM1, // GPIO14 Warm light GPIO_PWM2, // GPIO14 Warm light (PWM1 Warm)
GPIO_USER, // GPIO15 Optional sensor (PWM4 Blue) GPIO_USER, // GPIO15 Optional sensor (PWM4 Blue)
0, 0 0, 0
}, },

View File

@ -85,6 +85,7 @@
// -- HTTP ---------------------------------------- // -- HTTP ----------------------------------------
#define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +4k mem) - Disable by // #define USE_WEBSERVER // Enable web server and wifi manager (+62k code, +4k mem) - Disable by //
#define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin) #define WEB_SERVER 2 // [WebServer] Web server (0 = Off, 1 = Start as User, 2 = Start as Admin)
#define WEB_PORT 80 // Web server Port for User and Admin mode
#define WEB_USERNAME "admin" // Web server Admin mode user name #define WEB_USERNAME "admin" // Web server Admin mode user name
#define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable) #define WEB_PASSWORD "" // [WebPassword] Web server Admin mode Password for WEB_USERNAME (empty string = Disable)
#define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa #define FRIENDLY_NAME "Sonoff" // [FriendlyName] Friendlyname up to 32 characters used by webpages and Alexa

View File

@ -278,7 +278,7 @@ void startWebserver(int type, IPAddress ipweb)
if (!_httpflag) { if (!_httpflag) {
if (!webServer) { if (!webServer) {
webServer = new ESP8266WebServer(80); webServer = new ESP8266WebServer((type==HTTP_MANAGER)?80:WEB_PORT);
webServer->on("/", handleRoot); webServer->on("/", handleRoot);
webServer->on("/cn", handleConfig); webServer->on("/cn", handleConfig);
webServer->on("/md", handleModule); webServer->on("/md", handleModule);
@ -805,7 +805,7 @@ void handleSave()
{ {
if (httpUser()) return; if (httpUser()) return;
char log[LOGSZ], stemp[20]; char log[LOGSZ +20], stemp[20];
byte what = 0, restart; byte what = 0, restart;
String result = ""; String result = "";
@ -870,14 +870,16 @@ void handleSave()
addLog(LOG_LEVEL_INFO, log); addLog(LOG_LEVEL_INFO, log);
break; break;
case 6: case 6:
sysCfg.module = (!strlen(webServer->arg("mt").c_str())) ? MODULE : atoi(webServer->arg("mt").c_str()); byte new_module = (!strlen(webServer->arg("mt").c_str())) ? MODULE : atoi(webServer->arg("mt").c_str());
byte new_modflg = (sysCfg.module != new_module);
sysCfg.module = new_module;
mytmplt cmodule; mytmplt cmodule;
memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule)); memcpy_P(&cmodule, &modules[sysCfg.module], sizeof(cmodule));
String gpios = ""; String gpios = "";
for (byte i = 0; i < MAX_GPIO_PIN; i++) { for (byte i = 0; i < MAX_GPIO_PIN; i++) {
if (cmodule.gp.io[i] == GPIO_USER) { if (cmodule.gp.io[i] == GPIO_USER) {
snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i); snprintf_P(stemp, sizeof(stemp), PSTR("g%d"), i);
sysCfg.my_module.gp.io[i] = (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str()); sysCfg.my_module.gp.io[i] = (new_modflg) ? 0 : (!strlen(webServer->arg(stemp).c_str())) ? 0 : atoi(webServer->arg(stemp).c_str());
gpios += F(", GPIO"); gpios += String(i); gpios += F(" "); gpios += String(sysCfg.my_module.gp.io[i]); gpios += F(", GPIO"); gpios += String(i); gpios += F(" "); gpios += String(sysCfg.my_module.gp.io[i]);
} }
} }
@ -961,7 +963,7 @@ void handleUpgrade()
void handleUpgradeStart() void handleUpgradeStart()
{ {
if (httpUser()) return; if (httpUser()) return;
char svalue[16]; // was MESSZ char svalue[100]; // was MESSZ
addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Firmware upgrade start")); addLog_P(LOG_LEVEL_DEBUG, PSTR("HTTP: Firmware upgrade start"));
WIFI_configCounter(); WIFI_configCounter();

View File

@ -27,9 +27,6 @@ POSSIBILITY OF SUCH DAMAGE.
* Sonoff Led * Sonoff Led
\*********************************************************************************************/ \*********************************************************************************************/
#define ANALOG_WRITE_RANGE 255 // 127..1023 but as Color is addressed by 8 bits it should be 255 for my code
#define ANALOG_WRITE_FREQ 432 // 100..1000 Hz led refresh
uint8_t ledTable[] = { uint8_t ledTable[] = {
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@ -90,8 +87,8 @@ void sl_setDim(uint8_t myDimmer)
void sl_init(void) void sl_init(void)
{ {
analogWriteRange(ANALOG_WRITE_RANGE); // Default is 1023 (Arduino.h) sysCfg.pwmvalue[0] = 0; // We use led_color
analogWriteFreq(ANALOG_WRITE_FREQ); // Default is 1000 (core_esp8266_wiring_pwm.c) - Try to lower flicker sysCfg.pwmvalue[1] = 0; // We use led_color
sl_blankv = 0; sl_blankv = 0;
sl_power = 0; sl_power = 0;
sl_any = 0; sl_any = 0;
@ -104,11 +101,14 @@ void sl_blank(byte state)
// state = 0: No blank // state = 0: No blank
// 1: Blank led to solve flicker // 1: Blank led to solve flicker
/*
* Disabled when used with latest arduino-esp8266 pwm files
if (sysCfg.module == SONOFF_LED) { if (sysCfg.module == SONOFF_LED) {
sl_blankv = state; sl_blankv = state;
sl_wakeupActive = 0; sl_wakeupActive = 0;
sl_animate(); sl_animate();
} }
*/
} }
void sl_setPower(uint8_t power) void sl_setPower(uint8_t power)
@ -172,8 +172,8 @@ void sl_animate()
sl_lcolor[0] = sl_tcolor[0]; sl_lcolor[0] = sl_tcolor[0];
sl_lcolor[1] = sl_tcolor[1]; sl_lcolor[1] = sl_tcolor[1];
for (byte i = 0; i < 2; i++) { for (byte i = 0; i < 2; i++) {
if (pin[GPIO_PWM0 +i] < 99) { if (pin[GPIO_PWM1 +i] < 99) {
analogWrite(pin[GPIO_PWM0 +i], (sysCfg.led_table) ? ledTable[sl_lcolor[i]] : sl_lcolor[i]); analogWrite(pin[GPIO_PWM1 +i], ((sysCfg.led_table) ? ledTable[sl_lcolor[i]] : sl_lcolor[i]) * (PWM_RANGE / 255));
} }
} }
} }

View File

@ -438,19 +438,19 @@ boolean hlw_command(char *type, uint16_t index, char *dataBuf, uint16_t data_len
} }
else if (!strcmp(type,"HLWPCAL")) { else if (!strcmp(type,"HLWPCAL")) {
if ((data_len > 0) && (payload > 0) && (payload < 32001)) { if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
sysCfg.hlw_pcal = (payload == 1) ? HLW_PREF_PULSE : payload; sysCfg.hlw_pcal = (payload > 9999) ? payload : HLW_PREF_PULSE; // 12530
} }
snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.value_units) ? " uS" : ""); snprintf_P(svalue, ssvalue, PSTR("(\"HlwPcal\":\"%d%s\"}"), sysCfg.hlw_pcal, (sysCfg.value_units) ? " uS" : "");
} }
else if (!strcmp(type,"HLWUCAL")) { else if (!strcmp(type,"HLWUCAL")) {
if ((data_len > 0) && (payload > 0) && (payload < 32001)) { if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
sysCfg.hlw_ucal = (payload == 1) ? HLW_UREF_PULSE : payload; sysCfg.hlw_ucal = (payload > 999) ? payload : HLW_UREF_PULSE; // 1950
} }
snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.value_units) ? " uS" : ""); snprintf_P(svalue, ssvalue, PSTR("{\"HlwUcal\":\"%d%s\"}"), sysCfg.hlw_ucal, (sysCfg.value_units) ? " uS" : "");
} }
else if (!strcmp(type,"HLWICAL")) { else if (!strcmp(type,"HLWICAL")) {
if ((data_len > 0) && (payload > 0) && (payload < 32001)) { if ((data_len > 0) && (payload > 0) && (payload < 32001)) {
sysCfg.hlw_ical = (payload == 1) ? HLW_IREF_PULSE : payload; sysCfg.hlw_ical = (payload > 2499) ? payload : HLW_IREF_PULSE; // 3500
} }
snprintf_P(svalue, ssvalue, PSTR("{\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.value_units) ? " uS" : ""); snprintf_P(svalue, ssvalue, PSTR("{\"HlwIcal\":\"%d%s\"}"), sysCfg.hlw_ical, (sysCfg.value_units) ? " uS" : "");
} }