diff --git a/tasmota/i18n.h b/tasmota/i18n.h index f4fde64b3..fed6930d7 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -494,6 +494,24 @@ #define D_JSON_MOTOR_MIS "setMIS" #endif + // Commands xdrv_27_Shutter.ino + #ifdef USE_SHUTTER + #define D_PRFX_SHUTTER "Shutter" + #define D_CMND_SHUTTER_OPEN "Open" + #define D_CMND_SHUTTER_CLOSE "Close" + #define D_CMND_SHUTTER_STOP "Stop" + #define D_CMND_SHUTTER_POSITION "Position" + #define D_CMND_SHUTTER_OPENTIME "OpenDuration" + #define D_CMND_SHUTTER_CLOSETIME "CloseDuration" + #define D_CMND_SHUTTER_RELAY "Relay" + #define D_CMND_SHUTTER_SETHALFWAY "SetHalfway" + #define D_CMND_SHUTTER_SETCLOSE "SetClose" + #define D_CMND_SHUTTER_INVERT "Invert" + #define D_CMND_SHUTTER_CLIBRATION "Calibration" + #define D_CMND_SHUTTER_MOTORDELAY "MotorDelay" + #define D_CMND_SHUTTER_FREQUENCY "Frequency" + #endif + /********************************************************************************************/ // Log message prefix diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 8bc13dfa4..2338639a1 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -24,27 +24,10 @@ #define XDRV_27 27 -#define D_PRFX_SHUTTER "Shutter" -#define D_CMND_SHUTTER_OPEN "Open" -#define D_CMND_SHUTTER_CLOSE "Close" -#define D_CMND_SHUTTER_STOP "Stop" -#define D_CMND_SHUTTER_POSITION "Position" -#define D_CMND_SHUTTER_OPENTIME "OpenDuration" -#define D_CMND_SHUTTER_CLOSETIME "CloseDuration" -#define D_CMND_SHUTTER_RELAY "Relay" -#define D_CMND_SHUTTER_SETHALFWAY "SetHalfway" -#define D_CMND_SHUTTER_SETCLOSE "SetClose" -#define D_CMND_SHUTTER_INVERT "Invert" -#define D_CMND_SHUTTER_CLIBRATION "Calibration" -#define D_CMND_SHUTTER_MOTORDELAY "MotorDelay" -#define D_CMND_SHUTTER_FREQUENCY "Frequency" - #define D_SHUTTER "SHUTTER" const uint16_t MOTOR_STOP_TIME = 500; // in mS - - uint8_t calibrate_pos[6] = {0,30,50,70,90,100}; uint16_t messwerte[5] = {30,50,70,90,100}; @@ -82,9 +65,10 @@ struct SHUTTER { uint16_t close_velocity[MAX_SHUTTERS]; // in relation to open velocity. higher value = faster int8_t direction[MAX_SHUTTERS]; // 1 == UP , 0 == stop; -1 == down uint8_t mode = 0; // operation mode definition. see enum type above SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_OPEN__PULSE_CLOSE - uint8_t motordelay[MAX_SHUTTERS]; // initial motorstarttime in 0.05sec. + int16_t motordelay[MAX_SHUTTERS]; // initial motorstarttime in 0.05sec. uint16_t pwm_frequency; // frequency of PWN for stepper motors - uint16_t max_pwm_frequency = 1000; + uint16_t max_pwm_frequency = 1000; // maximum of PWM frequency that can be used. depend on the motor and drivers + uint8_t skip_relay_change; // avoid overrun at endstops } Shutter; void ShutterRtc50mS(void) @@ -99,7 +83,7 @@ int32_t ShutterPercentToRealPosition(uint8_t percent,uint8_t index) if (Settings.shutter_set50percent[index] != 50) { return percent <= 5 ? Settings.shuttercoeff[2][index] * percent : Settings.shuttercoeff[1][index] * percent + Settings.shuttercoeff[0][index]; } else { - uint32_t realpos; + int32_t realpos; // check against DIV 0 for (uint8_t j=0 ; j < 5 ; j++) { if (Settings.shuttercoeff[j][index] == 0) { @@ -133,7 +117,7 @@ uint8_t ShutterRealToPercentPosition(int32_t realpos, uint8_t index) if (Settings.shutter_set50percent[index] != 50) { return Settings.shuttercoeff[2][index] * 5 > realpos ? realpos / Settings.shuttercoeff[2][index] : (realpos-Settings.shuttercoeff[0][index]) / Settings.shuttercoeff[1][index]; } else { - uint16_t realpercent; + int16_t realpercent; for (uint8_t i=0 ; i < 5 ; i++) { if (realpos > Shutter.open_max[index] * calibrate_pos[i+1] / 100) { @@ -151,7 +135,7 @@ uint8_t ShutterRealToPercentPosition(int32_t realpos, uint8_t index) break; } } - return realpercent; + return (realpercent < 0 ? 0 : (realpercent > 100 ? 0 : realpercent)); } } @@ -257,7 +241,7 @@ void ShutterUpdatePosition(void) // Counter should be initiated to 0 to count movement. // 0..1000 in step 100 = 10 steps with 0.05 sec = 0.5sec total ramp time from start to // full speed. - if (pin[GPIO_PWM1+i] < 99 && Shutter.pwm_frequency != Shutter.max_pwm_frequency) { + if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE && pin[GPIO_PWM1+i] < 99 && Shutter.pwm_frequency != Shutter.max_pwm_frequency) { Shutter.pwm_frequency += Shutter.max_pwm_frequency/20; Shutter.pwm_frequency = (Shutter.pwm_frequency > Shutter.max_pwm_frequency ? Shutter.max_pwm_frequency : Shutter.pwm_frequency); analogWriteFreq(Shutter.pwm_frequency); @@ -266,7 +250,7 @@ void ShutterUpdatePosition(void) Shutter.real_position[i] = Shutter.start_position[i] + ( (Shutter.time[i] - Shutter.motordelay[i]) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i])); // avoid real position leaving the boundaries. - Shutter.real_position[i] = Shutter.real_position[i] < 0 ? 0 : (Shutter.real_position[i] > Shutter.open_max[i] ? Shutter.open_max[i] : Shutter.real_position[i]) ; + // Shutter.real_position[i] = Shutter.real_position[i] < 0 ? 0 : (Shutter.real_position[i] > Shutter.open_max[i] ? Shutter.open_max[i] : Shutter.real_position[i]) ; if (Shutter.real_position[i] * Shutter.direction[i] >= Shutter.target_position[i] * Shutter.direction[i] ) { @@ -295,8 +279,9 @@ void ShutterUpdatePosition(void) analogWrite(pin[GPIO_PWM1+i], 50); //prepare for stop PWM Shutter.motordelay[i] = -2 + Shutter.motordelay[i] + missing_steps/(Shutter.max_pwm_frequency/20); + Shutter.motordelay[i] = Shutter.motordelay[i] > 0 ? Shutter.motordelay[i] : 0; AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Missing steps %d, adjust motordelay %d, counter %d, temp realpos %d"), missing_steps, Shutter.motordelay[i],RtcSettings.pulse_counter[i] ,Shutter.real_position[i]); - Settings.shutter_motordelay[i]=(missing_steps > 0 ? Shutter.motordelay[i] : 0); + Settings.shutter_motordelay[i]=Shutter.motordelay[i]; analogWriteFreq(0); while (RtcSettings.pulse_counter[i] < (uint32_t)(Shutter.target_position[i]-Shutter.start_position[i])*Shutter.direction[i]*Shutter.max_pwm_frequency/2000) { delay(1); @@ -351,19 +336,35 @@ bool ShutterState(uint8_t device) (Shutter.mask & (1 << (Settings.shutter_startrelay[device]-1))) ); } -void ShutterStartInit(uint8_t index, uint8_t direction, int32_t target_pos) +void ShutterStartInit(uint8_t index, int8_t direction, int32_t target_pos) { - Shutter.direction[index] = direction; - Shutter.target_position[index] = target_pos; - Shutter.start_position[index] = Shutter.real_position[index]; - Shutter.time[index] = 0; - if (pin[GPIO_PWM1+index] < 99) { - Shutter.pwm_frequency = 0; - analogWriteFreq(Shutter.pwm_frequency); - analogWrite(pin[GPIO_PWM1+index], 0); - // can be operated without counter, but then not that acurate. - if (pin[GPIO_CNTR1+index] < 99) { - RtcSettings.pulse_counter[index] = 0; + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: dir %d, delta1 %d, delta2 %d, grant %d"),direction, (Shutter.open_max[index] - Shutter.real_position[index]) / Shutter.close_velocity[index], Shutter.real_position[index] / Shutter.close_velocity[index], 2+Shutter.motordelay[index]); + if (direction == 1 && (Shutter.open_max[index] - Shutter.real_position[index]) / Shutter.close_velocity[index] <= 2+Shutter.motordelay[index]) { + // shutter alread 100% cannot move further + // store relay number variable + Shutter.skip_relay_change = 1 ; + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: 100%% endstop already reached: Relay %d"),Shutter.skip_relay_change); + + } else if (direction == -1 && Shutter.real_position[index] / Shutter.close_velocity[index] <= 2+Shutter.motordelay[index]) { + // shutter already at 0% connot move into minus + // store relay number variable + Shutter.skip_relay_change = 1; + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: 0%% endstop already reached: Relay %d"),Shutter.skip_relay_change); + + } else { + Shutter.direction[index] = direction; + Shutter.target_position[index] = target_pos; + Shutter.start_position[index] = Shutter.real_position[index]; + Shutter.time[index] = 0; + Shutter.skip_relay_change = 0; + if (pin[GPIO_PWM1+index] < 99) { + Shutter.pwm_frequency = 0; + analogWriteFreq(Shutter.pwm_frequency); + analogWrite(pin[GPIO_PWM1+index], 0); + // can be operated without counter, but then not that acurate. + if (pin[GPIO_CNTR1+index] < 99) { + RtcSettings.pulse_counter[index] = 0; + } } } //AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start shutter: %d from %d to %d in directin %d"), index, Shutter.start_position[index], Shutter.target_position[index], Shutter.direction[index]); @@ -378,7 +379,7 @@ void ShutterDelayForMotorStop(void) void ShutterReportPosition(void) { uint16_t shutter_moving = 0; - for (uint32_t i = 0; i < shutters_present; i++) { + for (uint8_t i = 0; i < shutters_present; i++) { if (Shutter.direction[i] != 0) { char stemp1[20]; char stemp2[10]; @@ -414,7 +415,7 @@ void ShutterRelayChanged(void) switch (powerstate_local) { case 1: ShutterDelayForMotorStop(); - ShutterStartInit(i, 1, Shutter.open_max[i]); + ShutterStartInit(i, 1, Shutter.open_max[i]); break; case 3: ShutterDelayForMotorStop(); @@ -652,7 +653,7 @@ void CmndShutterSetClose(void) Shutter.real_position[XdrvMailbox.index -1] = 0; ShutterStartInit(XdrvMailbox.index -1, 0, 0); Settings.shutter_position[XdrvMailbox.index -1] = 0; - ResponseCmndChar(D_CONFIGURATION_RESET); + ResponseCmndIdxChar(D_CONFIGURATION_RESET); } } @@ -717,7 +718,7 @@ bool Xdrv27(uint8_t function) result = DecodeCommand(kShutterCommands, ShutterCommand); break; case FUNC_JSON_APPEND: - for (uint32_t i = 0; i < shutters_present; i++) { + for (uint8_t i = 0; i < shutters_present; i++) { uint8_t position = Settings.shutter_invert[i] ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]; ResponseAppend_P(","); ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter.direction[i]); @@ -731,10 +732,25 @@ bool Xdrv27(uint8_t function) case FUNC_SET_POWER: char stemp1[10]; // extract the number of the relay that was switched and save for later in Update Position. - Shutter.switched_relay = power ^ Shutter.old_power; - Shutter.old_power = power; + Shutter.switched_relay = XdrvMailbox.index ^ Shutter.old_power; AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Switched relay: %d by %s"), Shutter.switched_relay,GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource)); ShutterRelayChanged(); + Shutter.old_power = XdrvMailbox.index; + break; + case FUNC_SET_DEVICE_POWER: + if (Shutter.skip_relay_change ) { + uint8_t i; + for (i = 0; i < devices_present; i++) { + if (Shutter.switched_relay &1) { + break; + } + Shutter.switched_relay >>= 1; + } + //AddLog_P2(LOG_LEVEL_ERROR, PSTR("SHT: skip relay change: %d"),i+1); + result = true; + Shutter.skip_relay_change = 0; + ExecuteCommandPower(i+1, 0, SRC_SHUTTER); + } break; } }