diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index d23eafc96..8958e121c 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -578,6 +578,7 @@ void setup(void) { } if (RtcReboot.fast_reboot_count > Settings->param[P_BOOT_LOOP_OFFSET] +2) { // Restarted 4 times Settings->rule_enabled = 0; // Disable all rules + Settings->flag3.shutter_mode = 0; // disable shutter support TasmotaGlobal.no_autoexec = true; } if (RtcReboot.fast_reboot_count > Settings->param[P_BOOT_LOOP_OFFSET] +3) { // Restarted 5 times diff --git a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino index 84f5368fb..2ab1afa99 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_01_9_webserver.ino @@ -264,9 +264,6 @@ const char HTTP_MSG_SLIDER_GRADIENT[] PROGMEM = "
" "" "
"; -const char HTTP_MSG_SLIDER_SHUTTER[] PROGMEM = - "
" D_CLOSE "" D_OPEN "
" - "
"; const char HTTP_MSG_RSTRT[] PROGMEM = "
" D_DEVICE_WILL_RESTART "

"; @@ -1229,13 +1226,6 @@ void HandleRoot(void) } // Settings->flag3.pwm_multi_channels } #endif // USE_LIGHT -#ifdef USE_SHUTTER - if (Settings->flag3.shutter_mode) { // SetOption80 - Enable shutter support - for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { - WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, ShutterRealToPercentPosition(-9999, i), i+1); - } - } -#endif // USE_SHUTTER WSContentSend_P(HTTP_TABLE100); WSContentSend_P(PSTR("")); #ifdef USE_SONOFF_IFAN @@ -1258,7 +1248,7 @@ void HandleRoot(void) int32_t ShutterWebButton; if (ShutterWebButton = IsShutterWebButton(idx)) { WSContentSend_P(HTTP_DEVICE_CONTROL, 100 / cols, idx, - (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : ((Settings->shutter_options[abs(ShutterWebButton)-1] & 2) /* is locked */ ? "-" : ((Settings->shutter_options[abs(ShutterWebButton)-1] & 8) /* invert web buttons */ ? ((ShutterWebButton>0) ? "▼" : "▲") : ((ShutterWebButton>0) ? "▲" : "▼"))), + (set_button) ? SettingsText(SET_BUTTON1 + idx -1) : ((ShutterGetOptions(abs(ShutterWebButton)-1) & 2) /* is locked */ ? "-" : ((Settings->shutter_options[abs(ShutterWebButton)-1] & 8) /* invert web buttons */ ? ((ShutterWebButton>0) ? "▼" : "▲") : ((ShutterWebButton>0) ? "▲" : "▼"))), ""); } else { #endif // USE_SHUTTER @@ -1410,10 +1400,12 @@ bool HandleRootStatusRefresh(void) #endif // USE_LIGHT #ifdef USE_SHUTTER for (uint32_t j = 1; j <= TasmotaGlobal.shutters_present; j++) { + uint8_t percent; snprintf_P(webindex, sizeof(webindex), PSTR("u%d"), j); WebGetArg(webindex, tmp, sizeof(tmp)); // 0 - 100 percent + percent = atoi(tmp); if (strlen(tmp)) { - snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %s"), j, tmp); + snprintf_P(svalue, sizeof(svalue), PSTR("ShutterPosition%d %d"), j, (ShutterGetOptions(j-1) & 1) ? 100 - percent : percent); ExecuteWebCommand(svalue); } } diff --git a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino index ae31ab6cb..6fb523dc0 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_12_discovery.ino @@ -200,9 +200,9 @@ void TasDiscoverMessage(void) { light_controller_isCTRGBLinked, light_subtype); - for (uint32_t i = 0; i < tmin(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { #ifdef USE_SHUTTER - ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), Settings->shutter_options[i]); + ResponseAppend_P(PSTR("%s%d"), (i > 0 ? "," : ""), ShutterGetOptions(i)); #else ResponseAppend_P(PSTR("%s0"), (i > 0 ? "," : "")); #endif // USE_SHUTTER @@ -210,7 +210,7 @@ void TasDiscoverMessage(void) { ResponseAppend_P(PSTR("]," // Shutter Options (end) "\"sht\":[")); // Shutter Tilt (start) - for (uint32_t i = 0; i < tmax(TasmotaGlobal.shutters_present, MAX_SHUTTERS); i++) { + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { #ifdef USE_SHUTTER ResponseAppend_P(PSTR("%s[%d,%d,%d]"), (i > 0 ? "," : ""), ShutterGetTiltConfig(0,i), diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino index eb5569e4f..a4739135e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_esp32_shutter.ino @@ -54,7 +54,10 @@ #define D_ERROR_FILESYSTEM_NOT_READY "SHT: ERROR File system not enabled" #define D_ERROR_FILE_NOT_FOUND "SHT: ERROR File system not ready or file not found" -// +const char HTTP_MSG_SLIDER_SHUTTER[] PROGMEM = + "
%s%s
" + "
"; + const uint32_t SHUTTER_VERSION = 0x01010100; // Latest driver version (See settings deltas below) typedef struct { // depreciated 2023-04-28 @@ -364,7 +367,7 @@ bool ShutterStatus(void) { "\"Mode\":\"%d\"," "\"TiltConfig\":[%d,%d,%d,%d,%d]}"), i, ShutterSettings.shutter_startrelay[i], ShutterSettings.shutter_startrelay[i] +1, ShutterSettings.shutter_opentime[i], ShutterSettings.shutter_closetime[i], - ShutterSettings.shutter_set50percent[i], ShutterSettings.shutter_motordelay[i], GetBinary8(Settings->shutter_options[i], 4).c_str(), + ShutterSettings.shutter_set50percent[i], ShutterSettings.shutter_motordelay[i], GetBinary8(ShutterSettings.shutter_options[i], 4).c_str(), ShutterSettings.shuttercoeff[0][i], ShutterSettings.shuttercoeff[1][i], ShutterSettings.shuttercoeff[2][i], ShutterSettings.shuttercoeff[3][i], ShutterSettings.shuttercoeff[4][i], ShutterSettings.shutter_mode, ShutterSettings.shutter_tilt_config[0][i], ShutterSettings.shutter_tilt_config[1][i], ShutterSettings.shutter_tilt_config[2][i], ShutterSettings.shutter_tilt_config[3][i], ShutterSettings.shutter_tilt_config[4][i] @@ -389,6 +392,10 @@ uint8_t ShutterGetStartRelay(uint8_t index) { return ShutterSettings.shutter_startrelay[index]; } +uint8_t ShutterGetOptions(uint8_t index) { + return ShutterSettings.shutter_options[index]; +} + int8_t ShutterGetTiltConfig(uint8_t config_idx,uint8_t index) { return Shutter[index].tilt_config[config_idx]; } @@ -497,13 +504,13 @@ int32_t ShutterPercentToRealPosition(int16_t percent, uint32_t index) uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) { + int64_t realpercent; if (realpos == -9999) { realpos = Shutter[index].real_position; } if (ShutterSettings.shutter_set50percent[index] != 50) { - return (ShutterSettings.shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, ShutterSettings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-ShutterSettings.shuttercoeff[0][index]*10, ShutterSettings.shuttercoeff[1][index]); + realpercent = (ShutterSettings.shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, ShutterSettings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-ShutterSettings.shuttercoeff[0][index]*10, ShutterSettings.shuttercoeff[1][index]); } else { - int64_t realpercent; for (uint32_t j = 0; j < 5; j++) { if (realpos >= Shutter[index].open_max * calibrate_pos[j+1] / 100) { realpercent = SHT_DIV_ROUND(ShutterSettings.shuttercoeff[j][index], 10); @@ -521,10 +528,10 @@ uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) break; } } - realpercent = realpercent < 0 ? 0 : realpercent; - // if inverted recalculate the percentposition - return (ShutterSettings.shutter_options[index] & 1) ? 100 - realpercent : realpercent; } + realpercent = realpercent < 0 ? 0 : realpercent; + // if inverted recalculate the percentposition + return (ShutterSettings.shutter_options[index] & 1) ? 100 - realpercent : realpercent; } void ShutterInit(void) @@ -1127,8 +1134,8 @@ void ShutterRelayChanged(void) // powerstate_local == 1 => direction=1, target=Shutter[i].open_max // powerstate_local == 2 => direction=-1, target=0 // only happen on SHT_TIME // powerstate_local == 3 => direction=-1, target=0 // only happen if NOT SHT_TIME - int direction = (powerstate_local == 0) ? 0 : (powerstate_local == 1) ? 1 : -1; - int target = (powerstate_local == 1) ? Shutter[i].open_max : 0; + int8_t direction = (powerstate_local == 0) ? 0 : (powerstate_local == 1) ? 1 : -1; + int8_t target = (powerstate_local == 1) ? Shutter[i].open_max : 0; if (direction != 0) { ShutterStartInit(i, direction, target); @@ -1318,6 +1325,11 @@ void ShutterToggle(bool dir) } } +void ShutterShow(){ + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, (ShutterSettings.shutter_options[i] & 1) ? D_OPEN : D_CLOSE,(ShutterSettings.shutter_options[i] & 1) ? D_CLOSE : D_OPEN, ShutterRealToPercentPosition(-9999, i), i+1); + } +} /*********************************************************************************************\ * Commands \*********************************************************************************************/ @@ -2328,6 +2340,11 @@ bool Xdrv27(uint32_t function) result = false; } break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + ShutterShow(); + break; +#endif // USE_WEBSERVER } } return result; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino index 7229a8942..c9dbb9545 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_27_shutter.ino @@ -72,6 +72,10 @@ int32_t next_possible_stop_position = 0; int32_t current_real_position = 0; int32_t current_pwm_velocity = 0; +const char HTTP_MSG_SLIDER_SHUTTER[] PROGMEM = + "
%s%s
" + "
"; + const uint8_t MAX_MODES = 8; enum Shutterposition_mode {SHT_UNDEF, SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,SHT_AUTOCONFIG}; enum Shutterswitch_mode {SHT_SWITCH, SHT_PULSE,}; @@ -189,6 +193,10 @@ uint8_t ShutterGetStartRelay(uint8_t index) { return Settings->shutter_startrelay[index]; } +uint8_t ShutterGetOptions(uint8_t index) { + return Settings->shutter_options[index]; +} + int8_t ShutterGetTiltConfig(uint8_t config_idx,uint8_t index) { return Shutter[index].tilt_config[config_idx]; } @@ -259,6 +267,8 @@ void ShutterRtc50mS(void) int32_t ShutterPercentToRealPosition(int16_t percent, uint32_t index) { + // if inverted recalculate the percentposition + percent = (Settings->shutter_options[index] & 1) ? 100 - percent : percent; if (Settings->shutter_set50percent[index] != 50) { return (percent <= 5) ? Settings->shuttercoeff[2][index] * percent*10 : (Settings->shuttercoeff[1][index] * percent + (Settings->shuttercoeff[0][index]*10))*10; } else { @@ -295,13 +305,13 @@ int32_t ShutterPercentToRealPosition(int16_t percent, uint32_t index) uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) { + int64_t realpercent; if (realpos == -9999) { realpos = Shutter[index].real_position; } if (Settings->shutter_set50percent[index] != 50) { - return (Settings->shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, Settings->shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-Settings->shuttercoeff[0][index]*10, Settings->shuttercoeff[1][index]); + realpercent = (Settings->shuttercoeff[2][index] * 5 > realpos/10) ? SHT_DIV_ROUND(realpos/10, Settings->shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos/10-Settings->shuttercoeff[0][index]*10, Settings->shuttercoeff[1][index]); } else { - int64_t realpercent; for (uint32_t j = 0; j < 5; j++) { if (realpos >= Shutter[index].open_max * calibrate_pos[j+1] / 100) { realpercent = SHT_DIV_ROUND(Settings->shuttercoeff[j][index], 10); @@ -319,8 +329,10 @@ uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index) break; } } - return realpercent < 0 ? 0 : realpercent; } + realpercent = realpercent < 0 ? 0 : realpercent; + // if inverted recalculate the percentposition + return (Settings->shutter_options[index] & 1) ? 100 - realpercent : realpercent; } void ShutterInit(void) @@ -876,52 +888,38 @@ void ShutterRelayChanged(void) Shutter[i].tiltmoving = 0; } switch (ShutterGlobal.position_mode) { - // enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,}; - case SHT_TIME_UP_DOWN: - case SHT_COUNTER: - case SHT_PWM_VALUE: - case SHT_PWM_TIME: - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: power off manual change")); - ShutterPowerOff(i); - switch (powerstate_local) { - case 1: - ShutterStartInit(i, 1, Shutter[i].open_max); - break; - case 3: - ShutterStartInit(i, -1, 0); - break; - default: - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i); + // enum Shutterposition_mode {SHT_TIME, SHT_TIME_UP_DOWN, SHT_TIME_GARAGE, SHT_COUNTER, SHT_PWM_VALUE, SHT_PWM_TIME,}; + case SHT_TIME_UP_DOWN: + case SHT_COUNTER: + case SHT_PWM_VALUE: + case SHT_PWM_TIME: + case SHT_TIME: { + ShutterPowerOff(i); + // powerstate_local == 0 => direction=0, stop + // powerstate_local == 1 => direction=1, target=Shutter[i].open_max + // powerstate_local == 2 => direction=-1, target=0 // only happen on SHT_TIME + // powerstate_local == 3 => direction=-1, target=0 // only happen if NOT SHT_TIME + int8_t direction = (powerstate_local == 0) ? 0 : (powerstate_local == 1) ? 1 : -1; + int8_t target = (powerstate_local == 1) ? Shutter[i].open_max : 0; + + if (direction != 0) { + ShutterStartInit(i, direction, target); + } else { Shutter[i].target_position = Shutter[i].real_position; Shutter[i].last_stop_time = millis(); } - break; - case SHT_TIME: - switch (powerstate_local) { - case 1: - ShutterStartInit(i, 1, Shutter[i].open_max); - break; - case 2: - ShutterStartInit(i, -1, 0); - break; - default: - //AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Switch OFF motor."),i+1); - Shutter[i].target_position = Shutter[i].real_position; - Shutter[i].last_stop_time = millis(); + break; } - break; - case SHT_TIME_GARAGE: - switch (powerstate_local) { - case 1: - ShutterStartInit(i, Shutter[i].lastdirection*-1 , Shutter[i].lastdirection == 1 ? 0 : Shutter[i].open_max); - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Garage. NewTarget %d"), i, Shutter[i].target_position); - break; - default: - Shutter[i].target_position = Shutter[i].real_position; - } - - - } // switch (ShutterGlobal.position_mode) + case SHT_TIME_GARAGE: + switch (powerstate_local) { + case 1: + ShutterStartInit(i, Shutter[i].lastdirection * -1, Shutter[i].lastdirection == 1 ? 0 : Shutter[i].open_max); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d Garage. NewTarget %d"), i, Shutter[i].target_position); + break; + default: + Shutter[i].target_position = Shutter[i].real_position; + } + } AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Shtr%d, Target %ld, Power: %d, tiltmv: %d"), i+1, Shutter[i].target_position, powerstate_local,Shutter[i].tiltmoving); } // if (manual_relays_changed) } // for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) @@ -940,11 +938,11 @@ bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_ind bool ShutterButtonHandler(void) { - uint8_t buttonState = SHT_NOT_PRESSED; - uint8_t button = XdrvMailbox.payload; - uint8_t press_index; + uint8_t buttonState = SHT_NOT_PRESSED; + uint8_t button = XdrvMailbox.payload; + uint8_t press_index; uint32_t button_index = XdrvMailbox.index; - uint8_t shutter_index = Settings->shutter_button[button_index] & 0x03; + uint8_t shutter_index = Settings->shutter_button[button_index] & 0x03; uint16_t loops_per_second = 1000 / Settings->button_debounce; // ButtonDebounce (50) if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) { @@ -976,8 +974,8 @@ bool ShutterButtonHandler(void) Button.hold_timer[button_index] = 0; } else { Button.hold_timer[button_index]++; - if (!Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action - if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold + if (!Settings->flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action + if (Settings->param[P_HOLD_IGNORE] > 0) { // SetOption40 (0) - Do not ignore button hold if (Button.hold_timer[button_index] > loops_per_second * Settings->param[P_HOLD_IGNORE] / 10) { Button.hold_timer[button_index] = 0; // Reset button hold counter to stay below hold trigger Button.press_counter[button_index] = 0; // Discard button press to disable functionality @@ -1159,6 +1157,12 @@ void ShutterToggle(bool dir) } } +void ShutterShow(){ + for (uint32_t i = 0; i < TasmotaGlobal.shutters_present; i++) { + WSContentSend_P(HTTP_MSG_SLIDER_SHUTTER, (Settings->shutter_options[i] & 1) ? D_OPEN : D_CLOSE,(Settings->shutter_options[i] & 1) ? D_CLOSE : D_OPEN, ShutterRealToPercentPosition(-9999, i), i+1); + } +} + /*********************************************************************************************\ * Commands \*********************************************************************************************/ @@ -1980,6 +1984,11 @@ bool Xdrv27(uint32_t function) result = true; } break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + ShutterShow(); + break; +#endif // USE_WEBSERVER } } return result;