fixes and enhancements

- shutterposition now reports actual position if the shutter is moving #7686
- new RuleEvent: Shutter1#Target to get upfront info where the shutter is moving
- RuleExecution now every second to get an update of the current position
- New functionality for Stepper Motors. Now supporting 4 Stepper shutters working simultanously
This commit is contained in:
stefanbode 2020-02-24 12:23:03 +01:00 committed by GitHub
parent 86515b0714
commit 7a3a9bd364
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 70 additions and 59 deletions

View File

@ -48,7 +48,7 @@ void (* const ShutterCommand[])(void) PROGMEM = {
&CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay,
&CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime};
const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d}";
const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}";
const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}";
#include <Ticker.h>
@ -70,7 +70,7 @@ struct SHUTTER {
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
int16_t motordelay[MAX_SHUTTERS]; // initial motorstarttime in 0.05sec.
int16_t pwm_frequency; // frequency of PWN for stepper motors
int16_t pwm_frequency[MAX_SHUTTERS]; // frequency of PWN for stepper motors
uint16_t max_pwm_frequency = 1000; // maximum of PWM frequency for openig the shutter. depend on the motor and drivers
uint16_t max_close_pwm_frequency[MAX_SHUTTERS];// maximum of PWM frequency for closeing the shutter. depend on the motor and drivers
uint8_t skip_relay_change; // avoid overrun at endstops
@ -82,17 +82,18 @@ void ShutterLogPos(uint32_t i)
char stemp2[10];
dtostrfd((float)Shutter.time[i] / steps_per_second, 2, stemp2);
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter%d Real %d, Start %d, Stop %d, Dir %d, Delay %d, Rtc %s [s], Freq %d"),
i+1, Shutter.real_position[i], Shutter.start_position[i], Shutter.target_position[i], Shutter.direction[i], Shutter.motordelay[i], stemp2, Shutter.pwm_frequency);
i+1, Shutter.real_position[i], Shutter.start_position[i], Shutter.target_position[i], Shutter.direction[i], Shutter.motordelay[i], stemp2, Shutter.pwm_frequency[i]);
}
void ShutterRtc50mS(void)
{
for (uint32_t i = 0; i < shutters_present; i++) {
for (uint8_t i = 0; i < shutters_present; i++) {
Shutter.time[i]++;
if (Shutter.accelerator[i]) {
Shutter.pwm_frequency += Shutter.accelerator[i];
Shutter.pwm_frequency = tmax(0,tmin(Shutter.direction[i]==1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i],Shutter.pwm_frequency));
analogWriteFreq(Shutter.pwm_frequency);
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: accelerator i=%d -> %d"),i, Shutter.accelerator[i]);
Shutter.pwm_frequency[i] += Shutter.accelerator[i];
Shutter.pwm_frequency[i] = tmax(0,tmin(Shutter.direction[i]==1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i],Shutter.pwm_frequency[i]));
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 50);
}
}
@ -102,8 +103,6 @@ void ShutterRtc50mS(void)
int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
{
if (0 == percent) return 0;
if (100 == percent) return Shutter.open_max[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 {
@ -138,8 +137,6 @@ int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index)
{
if (0 >= realpos) return 0;
if (Shutter.open_max[index] <= realpos) return 100;
if (Settings.shutter_set50percent[index] != 50) {
return (Settings.shuttercoeff[2][index] * 5 > realpos) ? SHT_DIV_ROUND(realpos, Settings.shuttercoeff[2][index]) : SHT_DIV_ROUND(realpos-Settings.shuttercoeff[0][index], Settings.shuttercoeff[1][index]);
} else {
@ -203,8 +200,9 @@ void ShutterInit(void)
Shutter.mode = SHT_OFF_ON__OPEN_CLOSE;
if ((pin[GPIO_PWM1+i] < 99) && (pin[GPIO_CNTR1+i] < 99)) {
Shutter.mode = SHT_OFF_ON__OPEN_CLOSE_STEPPER;
Shutter.pwm_frequency = 0;
analogWriteFreq(Shutter.pwm_frequency);
Shutter.pwm_frequency[i] = 0;
Shutter.accelerator[i] = 0;
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 50);
}
}
@ -256,29 +254,24 @@ void ShutterInit(void)
void ShutterReportPosition(bool always)
{
uint32_t shutter_moving = 0;
Response_P(PSTR("{"));
for (uint32_t i = 0; i < shutters_present; i++) {
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d: Real Pos: %d"), i+1,Shutter.real_position[i]);
uint32_t position = ShutterRealToPercentPosition(Shutter.real_position[i], i);
if (Shutter.direction[i] != 0) {
shutter_moving = 1;
rules_flag.shutter_moving = 1;
ShutterLogPos(i);
}
if (i) { ResponseAppend_P(PSTR(",")); }
ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings.shutter_options[i] & 1) ? 100-position : position, Shutter.direction[i]);
ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings.shutter_options[i] & 1) ? 100-position : position, Shutter.direction[i], ShutterRealToPercentPosition(Shutter.target_position[i], i));
}
ResponseJsonEnd();
if (always || (1 == shutter_moving)) {
if (always || (rules_flag.shutter_moving)) {
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER));
XdrvRulesProcess();
}
if (rules_flag.shutter_moving > shutter_moving) {
rules_flag.shutter_moved = 1;
} else {
rules_flag.shutter_moved = 0;
}
rules_flag.shutter_moving = shutter_moving;
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), rules_flag.shutter_moving, rules_flag.shutter_moved);
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), rules_flag.shutter_moving, rules_flag.shutter_moved);
}
void ShutterLimitRealAndTargetPositions(uint32_t i) {
@ -304,22 +297,22 @@ void ShutterUpdatePosition(void)
int32_t max_frequency = Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i];
int32_t max_freq_change_per_sec = Shutter.max_pwm_frequency*steps_per_second / (Shutter.motordelay[i]>0 ? Shutter.motordelay[i] : 1);
int32_t min_runtime_ms = Shutter.pwm_frequency*1000 / max_freq_change_per_sec;
int32_t min_runtime_ms = Shutter.pwm_frequency[i]*1000 / max_freq_change_per_sec;
int32_t velocity = Shutter.direction[i] == 1 ? 100 : Shutter.close_velocity[i];
int32_t minstopway = min_runtime_ms * velocity / 100 * Shutter.pwm_frequency / max_frequency * Shutter.direction[i] ;
int32_t minstopway = min_runtime_ms * velocity / 100 * Shutter.pwm_frequency[i] / max_frequency * Shutter.direction[i] ;
int32_t next_possible_stop = Shutter.real_position[i] + minstopway ;
stop_position_delta =200 * Shutter.pwm_frequency/max_frequency + Shutter.direction[i] * (next_possible_stop - Shutter.target_position[i]);
stop_position_delta =200 * Shutter.pwm_frequency[i]/max_frequency + Shutter.direction[i] * (next_possible_stop - Shutter.target_position[i]);
//Shutter.accelerator[i] = tmin(tmax(max_freq_change_per_sec*(100-(Shutter.direction[i]*(Shutter.target_position[i]-next_possible_stop) ))/2000 , max_freq_change_per_sec*9/200), max_freq_change_per_sec*11/200);
//int32_t act_freq_change = max_freq_change_per_sec/20;
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: time: %d, velocity %d, minstopway %d,cur_freq %d, max_frequency %d, act_freq_change %d, min_runtime_ms %d, act.pos %d, next_stop %d, target: %d"),Shutter.time[i],velocity,minstopway,
Shutter.pwm_frequency,max_frequency, Shutter.accelerator[i],min_runtime_ms,Shutter.real_position[i], next_possible_stop,Shutter.target_position[i]);
Shutter.pwm_frequency[i],max_frequency, Shutter.accelerator[i],min_runtime_ms,Shutter.real_position[i], next_possible_stop,Shutter.target_position[i]);
if (Shutter.accelerator[i] < 0 || next_possible_stop * Shutter.direction[i] > Shutter.target_position[i] * Shutter.direction[i] ) {
Shutter.accelerator[i] = - tmin(tmax(max_freq_change_per_sec*(100-(Shutter.direction[i]*(Shutter.target_position[i]-next_possible_stop) ))/2000 , max_freq_change_per_sec*9/200), max_freq_change_per_sec*12/200);
//AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Ramp down: acc: %d"), Shutter.accelerator[i]);
} else if ( Shutter.accelerator[i] > 0 && Shutter.pwm_frequency == max_frequency) {
} else if ( Shutter.accelerator[i] > 0 && Shutter.pwm_frequency[i] == max_frequency) {
Shutter.accelerator[i] = 0;
}
} else {
@ -343,13 +336,13 @@ void ShutterUpdatePosition(void)
case SHT_OFF_ON__OPEN_CLOSE_STEPPER:
missing_steps = ((Shutter.target_position[i]-Shutter.start_position[i])*Shutter.direction[i]*Shutter.max_pwm_frequency/2000) - RtcSettings.pulse_counter[i];
//prepare for stop PWM
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Remain steps %d, counter %d, freq %d"), missing_steps, RtcSettings.pulse_counter[i] ,Shutter.pwm_frequency);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Remain steps %d, counter %d, freq %d"), missing_steps, RtcSettings.pulse_counter[i] ,Shutter.pwm_frequency[i]);
Shutter.accelerator[i] = 0;
Shutter.pwm_frequency = Shutter.pwm_frequency > 250 ? 250 : Shutter.pwm_frequency;
analogWriteFreq(Shutter.pwm_frequency);
Shutter.pwm_frequency[i] = Shutter.pwm_frequency[i] > 250 ? 250 : Shutter.pwm_frequency[i];
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 50);
Shutter.pwm_frequency = 0;
analogWriteFreq(Shutter.pwm_frequency);
Shutter.pwm_frequency[i] = 0;
analogWriteFreq(Shutter.pwm_frequency[i]);
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);
}
@ -391,6 +384,7 @@ void ShutterUpdatePosition(void)
Shutter.direction[i] = 0;
ShutterReportPosition(true);
rules_flag.shutter_moved = 1;
XdrvRulesProcess();
}
}
@ -413,8 +407,8 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
Shutter.skip_relay_change = 1;
} else {
if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) {
Shutter.pwm_frequency = 0;
analogWriteFreq(Shutter.pwm_frequency);
Shutter.pwm_frequency[i] = 0;
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 0);
// can be operated without counter, but then not that acurate.
if (pin[GPIO_CNTR1+i] < 99) {
@ -435,14 +429,16 @@ void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
void ShutterWaitForMotorStop(uint32_t i)
{
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Wait for Motorstop.."));
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Wait for Motorstop..dir %d, akt freq: %d, max %d, maxclose %d"),Shutter.direction[i],Shutter.pwm_frequency[i], Shutter.max_pwm_frequency, Shutter.max_close_pwm_frequency[i]);
if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) {
if (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode) {
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Frequency change %d"), Shutter.pwm_frequency);
while (Shutter.pwm_frequency > 0) {
Shutter.accelerator[i] = 0;
Shutter.pwm_frequency = tmax(Shutter.pwm_frequency-((Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i])/(Shutter.motordelay[i]+1)) , 0);
analogWriteFreq(Shutter.pwm_frequency);
while (Shutter.pwm_frequency[i] > 0) {
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Frequency: %ld, delta: %d"), Shutter.pwm_frequency[i], (int32_t)((Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i])/(Shutter.motordelay[i]+1)) );
Shutter.pwm_frequency[i] = tmax(Shutter.pwm_frequency[i]-((Shutter.direction[i] == 1 ? Shutter.max_pwm_frequency : Shutter.max_close_pwm_frequency[i])/(Shutter.motordelay[i]+1)) , 0);
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Frequency: %ld"), Shutter.pwm_frequency[i]);
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 50);
delay(50);
}
@ -532,7 +528,10 @@ void ShutterButtonHandler(void)
uint8_t shutter_index = Settings.shutter_button[button_index] & 0x03;
uint16_t loops_per_second = 1000 / Settings.button_debounce; // ButtonDebounce (50)
if ( button != Button.last_state[button_index]) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: shutter %d, button %d, presstate %d, lasttate %d, Settings.flag.button_single %d)"), shutter_index+1, button_index+1, button, Button.last_state[button_index], Settings.flag.button_single);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Button.press_counter[button_index] %d, Button.hold_timer[button_index] %d, Button.window_timer[button_index] %d "), Button.press_counter[button_index], Button.hold_timer[button_index], Button.window_timer[button_index] );
}
if ((PRESSED == button) && (NOT_PRESSED == Button.last_state[button_index])) {
if (Settings.flag.button_single) { // SetOption13 (0) - Allow only single button press for immediate action
buttonState = SHT_PRESSED_MULTI;
@ -542,9 +541,10 @@ void ShutterButtonHandler(void)
buttonState = SHT_PRESSED_IMMEDIATE;
press_index = 1;
Button.press_counter[button_index] = 99; // Remember to discard further action for press & hold within button timings
} else
} else {
Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1;
Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window
Button.window_timer[button_index] = loops_per_second / 2; // 0.5 second multi press window
}
}
blinks = 201;
}
@ -596,14 +596,18 @@ void ShutterButtonHandler(void)
// check for simultaneous shutter button press
uint32 min_shutterbutton_press_counter = -1;
for (uint32_t i = 0; i < MAX_KEYS; i++) {
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (Button.press_counter[i] < min_shutterbutton_press_counter))
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Settings.shutter_button[i] %ld, shutter_index %d, Button.press_counter[i] %d, min_shutterbutton_press_counter %d"), Settings.shutter_button[i], shutter_index, Button.press_counter[i] , min_shutterbutton_press_counter);
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) != shutter_index) && (Button.press_counter[i] < min_shutterbutton_press_counter)) {
min_shutterbutton_press_counter = Button.press_counter[i];
}
}
if (min_shutterbutton_press_counter == Button.press_counter[button_index]) {
// simultaneous shutter button press detected
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT:simultanous presss deteced"));
press_index = Button.press_counter[button_index];
for (uint32_t i = 0; i < MAX_KEYS; i++)
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index))
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) != shutter_index))
Button.press_counter[i] = 99; // Remember to discard further action for press & hold within button timings
buttonState = SHT_PRESSED_MULTI_SIMULTANEOUS;
}
@ -617,9 +621,13 @@ void ShutterButtonHandler(void)
}
}
}
if (buttonState) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Final buttonState %d"), buttonState);
}
if (buttonState != SHT_NOT_PRESSED) {
if (buttonState == SHT_PRESSED_MULTI_SIMULTANEOUS) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: SHT_PRESSED_MULTI_SIMULTANEOUS"));
if ((press_index>=5) && (press_index<=7) && (!Settings.flag.button_restrict)) { // 5x..7x && no SetOption1 (0)
// simultaneous shutter button press 5x, 6x, 7x detected
char scmnd[20];
@ -628,7 +636,7 @@ void ShutterButtonHandler(void)
return;
}
} else if (buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS) {
// simultaneous shutter button extend hold detected
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: SHT_PRESSED_EXT_HOLD_SIMULTANEOUS"));// simultaneous shutter button extend hold detected
if (!Settings.flag.button_restrict) { // no SetOption1 (0)
char scmnd[20];
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
@ -636,6 +644,7 @@ void ShutterButtonHandler(void)
return;
}
} else if (buttonState <= SHT_PRESSED_IMMEDIATE) {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: SHT_PRESSED_IMMEDIATE"));
if (Settings.shutter_startrelay[shutter_index] && Settings.shutter_startrelay[shutter_index] <9) {
uint8_t pos_press_index = (buttonState == SHT_PRESSED_HOLD) ? 3 : (press_index-1);
if (pos_press_index>3) pos_press_index=3;
@ -647,14 +656,15 @@ void ShutterButtonHandler(void)
XdrvMailbox.data = databuf;
XdrvMailbox.command = NULL;
if (buttonState == SHT_PRESSED_IMMEDIATE) {
XdrvMailbox.payload = XdrvMailbox.index;
CmndShutterStop();
}
else {
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: SHT_PRESSED_IMMEDIATE stop"));
//XdrvMailbox.payload = XdrvMailbox.index;
//CmndShutterStop();
} else {
uint8_t position = (Settings.shutter_button[button_index]>>(6*pos_press_index + 2)) & 0x03f;
if (position) {
if (Shutter.direction[shutter_index]) {
XdrvMailbox.payload = XdrvMailbox.index;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: immegency stop"));
CmndShutterStop();
} else {
XdrvMailbox.payload = position = (position-1)<<1;
@ -670,12 +680,12 @@ void ShutterButtonHandler(void)
Response_P("%d", position);
MqttPublish(stopic, false);
}
}
}
}
}
}
}
} // for (uint32_t)
} // if (Settings.shutter)
} // ende else
} // if (position)
} // end else
} // if if (Settings.shutter_startrelay[shutter_index]
}
Response_P(PSTR("{"));
ResponseAppend_P(JSON_SHUTTER_BUTTON, shutter_index+1, (buttonState <= SHT_PRESSED_IMMEDIATE) ? (button_index+1) : 0, press_index);
@ -756,6 +766,7 @@ void CmndShutterPosition(void)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Pos. in: payload %s (%d), payload %d, idx %d, src %d"), XdrvMailbox.data , XdrvMailbox.data_len, XdrvMailbox.payload , XdrvMailbox.index, last_source );
// value 0 with data_len > 0 can mean Open
// special handling fo UP,DOWN,TOGGLE,STOP command comming with payload -99
if ((XdrvMailbox.data_len > 1) && (XdrvMailbox.payload <= 0)) {
//UpperCase(XdrvMailbox.data, XdrvMailbox.data);
if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_UP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_OPEN) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEUP))) {
@ -773,13 +784,13 @@ void CmndShutterPosition(void)
}
}
int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? 0 : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload);
int8_t target_pos_percent = (XdrvMailbox.payload < 0) ? (XdrvMailbox.payload == -99 ? ShutterRealToPercentPosition(Shutter.real_position[index], index) : 0) : ((XdrvMailbox.payload > 100) ? 100 : XdrvMailbox.payload);
// webgui still send also on inverted shutter the native position.
target_pos_percent = ((Settings.shutter_options[index] & 1) && (SRC_WEBGUI != last_source)) ? 100 - target_pos_percent : target_pos_percent;
if (XdrvMailbox.payload != -99) {
//target_pos_percent = (Settings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent;
Shutter.target_position[index] = ShutterPercentToRealPosition(target_pos_percent, index);
Shutter.accelerator[index] = Shutter.max_pwm_frequency / ((Shutter.motordelay[index] > 0) ? Shutter.motordelay[index] : 1);
//Shutter.accelerator[index] = Shutter.max_pwm_frequency / ((Shutter.motordelay[index] > 0) ? Shutter.motordelay[index] : 1);
//Shutter.target_position[index] = XdrvMailbox.payload < 5 ? Settings.shuttercoeff[2][index] * XdrvMailbox.payload : Settings.shuttercoeff[1][index] * XdrvMailbox.payload + Settings.shuttercoeff[0,index];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: lastsource %d:, real %d, target %d, payload %d"), last_source, Shutter.real_position[index] ,Shutter.target_position[index],target_pos_percent);
}