Tasmota/tasmota/xdrv_27_shutter.ino

1232 lines
62 KiB
Arduino
Raw Normal View History

/*
xdrv_27_shutter.ino - Shutter/Blind support for Tasmota
2019-12-31 13:23:34 +00:00
Copyright (C) 2020 Stefan Bode
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef USE_SHUTTER
/*********************************************************************************************\
* Shutter or Blind support using two consecutive relays
\*********************************************************************************************/
#define XDRV_27 27
#define D_SHUTTER "SHUTTER"
const uint16_t MOTOR_STOP_TIME = 500; // in mS
const uint8_t steps_per_second = 20; // FUNC_EVERY_50_MSECOND
uint8_t calibrate_pos[6] = {0,30,50,70,90,100};
uint16_t messwerte[5] = {30,50,70,90,100};
uint16_t last_execute_step;
enum ShutterModes { SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_OPEN__PULSE_CLOSE, SHT_OFF_ON__OPEN_CLOSE_STEPPER,};
enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE, SHT_PRESSED_EXT_HOLD, SHT_PRESSED_MULTI_SIMULTANEOUS, SHT_PRESSED_HOLD_SIMULTANEOUS, SHT_PRESSED_EXT_HOLD_SIMULTANEOUS,};
const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|"
D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|"
D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|"
D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|"
2020-03-10 07:41:37 +00:00
D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS;
void (* const ShutterCommand[])(void) PROGMEM = {
&CmndShutterOpen, &CmndShutterClose, &CmndShutterStop, &CmndShutterPosition,
&CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay,
&CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay,
2020-03-10 07:41:37 +00:00
&CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons};
const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}";
2020-01-22 12:23:59 +00:00
const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}";
#include <Ticker.h>
Ticker TickerShutter;
struct SHUTTER {
power_t mask = 0; // bit mask with 11 at the position of relays that belong to at least ONE shutter
power_t old_power = 0; // preserve old bitmask for power to extract the relay that changes.
power_t switched_relay = 0; // bitmatrix that contain the relays that was lastly changed.
uint32_t time[MAX_SHUTTERS]; // operating time of the shutter in 0.05sec
int32_t open_max[MAX_SHUTTERS]; // max value on maximum open calculated
int32_t target_position[MAX_SHUTTERS]; // position to go to
int32_t start_position[MAX_SHUTTERS]; // position before a movement is started. init at start
int32_t real_position[MAX_SHUTTERS]; // value between 0 and Shutter.open_max
uint16_t open_time[MAX_SHUTTERS]; // duration to open the shutter. 112 = 11.2sec
uint16_t close_time[MAX_SHUTTERS]; // duration to close the shutter. 112 = 11.2sec
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
int16_t motordelay[MAX_SHUTTERS]; // initial motorstarttime in 0.05sec.
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
int32_t accelerator[MAX_SHUTTERS]; // speed of ramp-up, ramp down of shutter
uint8_t start_reported = 0;
} Shutter;
2020-01-04 14:09:57 +00:00
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]);
2020-01-04 14:09:57 +00:00
}
void ShutterRtc50mS(void)
{
for (uint8_t i = 0; i < shutters_present; i++) {
Shutter.time[i]++;
if (Shutter.accelerator[i]) {
//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);
}
}
}
#define SHT_DIV_ROUND(__A, __B) (((__A) + (__B)/2) / (__B))
2020-01-04 14:09:57 +00:00
int32_t ShutterPercentToRealPosition(uint32_t percent, uint32_t index)
{
if (Settings.shutter_set50percent[index] != 50) {
2020-01-04 14:09:57 +00:00
return (percent <= 5) ? Settings.shuttercoeff[2][index] * percent : Settings.shuttercoeff[1][index] * percent + Settings.shuttercoeff[0][index];
} else {
uint32_t realpos;
// check against DIV 0
2020-01-04 14:09:57 +00:00
for (uint32_t j = 0; j < 5; j++) {
if (0 == Settings.shuttercoeff[j][index]) {
AddLog_P2(LOG_LEVEL_ERROR, PSTR("SHT: RESET/INIT CALIBRATION MATRIX DIV 0"));
2020-01-04 14:09:57 +00:00
for (uint32_t k = 0; k < 5; k++) {
Settings.shuttercoeff[k][index] = SHT_DIV_ROUND(calibrate_pos[k+1] * 1000, calibrate_pos[5]);
}
}
}
2020-01-04 14:09:57 +00:00
for (uint32_t i = 0; i < 5; i++) {
2020-01-13 11:00:34 +00:00
if ((percent * 10) >= Settings.shuttercoeff[i][index]) {
realpos = SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i+1], 100);
//AddLog_P2(LOG_LEVEL_INFO, PSTR("Realposition TEMP1: %d, %% %d, coeff %d"), realpos, percent, Settings.shuttercoeff[i][index]);
} else {
2020-01-04 14:09:57 +00:00
if (0 == i) {
realpos = SHT_DIV_ROUND(SHT_DIV_ROUND(percent * Shutter.open_max[index] * calibrate_pos[i+1], Settings.shuttercoeff[i][index]), 10);
} else {
//uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100;
//AddLog_P2(LOG_LEVEL_INFO, PSTR("Realposition TEMP2: %d, %% %d, coeff %d"), addon, (calibrate_pos[i+1] - calibrate_pos[i]), (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]));
realpos += SHT_DIV_ROUND(SHT_DIV_ROUND((percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter.open_max[index] * (calibrate_pos[i+1] - calibrate_pos[i]), Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), 100);
}
break;
}
}
2020-01-04 14:09:57 +00:00
return realpos;
}
}
2020-01-04 14:09:57 +00:00
uint8_t ShutterRealToPercentPosition(int32_t realpos, uint32_t index)
{
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 {
uint16_t realpercent;
2020-01-04 14:09:57 +00:00
for (uint32_t i = 0; i < 5; i++) {
if (realpos >= Shutter.open_max[index] * calibrate_pos[i+1] / 100) {
realpercent = SHT_DIV_ROUND(Settings.shuttercoeff[i][index], 10);
//AddLog_P2(LOG_LEVEL_INFO, PSTR("Realpercent TEMP1: %d, %% %d, coeff %d"), realpercent, realpos, Shutter_Open_Max[index] * calibrate_pos[i+1] / 100);
} else {
2020-01-04 14:09:57 +00:00
if (0 == i) {
realpercent = SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * Settings.shuttercoeff[i][index], calibrate_pos[i+1]), Shutter.open_max[index]);
} else {
//uint16_t addon = ( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]) / (calibrate_pos[i+1] - calibrate_pos[i])/ Shutter_Open_Max[index];
//uint16_t addon = ( percent*10 - Settings.shuttercoeff[i-1][index] ) * Shutter_Open_Max[index] * (calibrate_pos[i+1] - calibrate_pos[i]) / (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]) / 100;
//AddLog_P2(LOG_LEVEL_INFO, PSTR("Realpercent TEMP2: %d, delta %d, %% %d, coeff %d"), addon,( realpos - (Shutter_Open_Max[index] * calibrate_pos[i] / 100) ) , (calibrate_pos[i+1] - calibrate_pos[i])* Shutter_Open_Max[index]/100, (Settings.shuttercoeff[i][index] -Settings.shuttercoeff[i-1][index]));
realpercent += SHT_DIV_ROUND(SHT_DIV_ROUND((realpos - SHT_DIV_ROUND(Shutter.open_max[index] * calibrate_pos[i], 100)) * 10 * (Settings.shuttercoeff[i][index] - Settings.shuttercoeff[i-1][index]), (calibrate_pos[i+1] - calibrate_pos[i])), Shutter.open_max[index]) ;
}
break;
}
}
return realpercent;
}
}
void ShutterInit(void)
{
shutters_present = 0;
Shutter.mask = 0;
//Initialize to get relay that changed
Shutter.old_power = power;
bool relay_in_interlock = false;
// if shutter 4 is unused
if (Settings.shutter_startrelay[MAX_SHUTTERS] == 0) {
Shutter.max_pwm_frequency = Settings.shuttercoeff[4][3] > 0 ? Settings.shuttercoeff[4][3] : Shutter.max_pwm_frequency;
}
for (uint32_t i = 0; i < MAX_SHUTTERS; i++) {
// set startrelay to 1 on first init, but only to shutter 1. 90% usecase
Settings.shutter_startrelay[i] = (Settings.shutter_startrelay[i] == 0 && i == 0? 1 : Settings.shutter_startrelay[i]);
2020-01-04 14:09:57 +00:00
if (Settings.shutter_startrelay[i] && (Settings.shutter_startrelay[i] < 9)) {
shutters_present++;
// Determine shutter types
Shutter.mask |= 3 << (Settings.shutter_startrelay[i] -1) ;
2019-11-03 11:33:36 +00:00
for (uint32_t j = 0; j < MAX_INTERLOCKS * Settings.flag.interlock; j++) { // CMND_INTERLOCK - Enable/disable interlock
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Interlock state i=%d %d, flag %d, , shuttermask %d, maskedIL %d"),i, Settings.interlock[i], Settings.flag.interlock,Shutter.mask, Settings.interlock[i]&Shutter.mask);
2020-01-04 14:09:57 +00:00
if (Settings.interlock[j] && (Settings.interlock[j] & Shutter.mask)) {
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Relay in Interlock group"));
relay_in_interlock = true;
}
}
if (relay_in_interlock) {
if (Settings.pulse_timer[i] > 0) {
Shutter.mode = SHT_PULSE_OPEN__PULSE_CLOSE;
} else {
Shutter.mode = SHT_OFF_OPEN__OFF_CLOSE;
}
} else {
Shutter.mode = SHT_OFF_ON__OPEN_CLOSE;
2020-01-04 14:09:57 +00:00
if ((pin[GPIO_PWM1+i] < 99) && (pin[GPIO_CNTR1+i] < 99)) {
Shutter.mode = SHT_OFF_ON__OPEN_CLOSE_STEPPER;
Shutter.pwm_frequency[i] = 0;
Shutter.accelerator[i] = 0;
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 50);
}
}
TickerShutter.attach_ms(50, ShutterRtc50mS );
// default the 50 percent should not have any impact without changing it. set to 60
2020-01-04 14:09:57 +00:00
Settings.shutter_set50percent[i] = (Settings.shutter_set50percent[i] > 0) ? Settings.shutter_set50percent[i] : 50;
// use 10 sec. as default to allow everybody to play without deep initialize
2020-01-04 14:09:57 +00:00
Shutter.open_time[i] = (Settings.shutter_opentime[i] > 0) ? Settings.shutter_opentime[i] : 100;
Shutter.close_time[i] = (Settings.shutter_closetime[i] > 0) ? Settings.shutter_closetime[i] : 100;
// Update Calculation 20 because time interval is 0.05 sec
Shutter.open_max[i] = 200 * Shutter.open_time[i];
2020-01-04 14:09:57 +00:00
Shutter.close_velocity[i] = Shutter.open_max[i] / Shutter.close_time[i] / 2 ;
Shutter.max_close_pwm_frequency[i] = Shutter.max_pwm_frequency*Shutter.open_time[i] / Shutter.close_time[i];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d Closefreq: %d"),i, Shutter.max_close_pwm_frequency[i]);
// calculate a ramp slope at the first 5 percent to compensate that shutters move with down part later than the upper part
if (Settings.shutter_set50percent[i] != 50) {
Settings.shuttercoeff[1][i] = Shutter.open_max[i] * (100 - Settings.shutter_set50percent[i] ) / 5000;
Settings.shuttercoeff[0][i] = Shutter.open_max[i] - (Settings.shuttercoeff[1][i] * 100);
Settings.shuttercoeff[2][i] = (Settings.shuttercoeff[0][i] + 5 * Settings.shuttercoeff[1][i]) / 5;
}
2020-01-04 14:09:57 +00:00
Shutter.mask |= 3 << (Settings.shutter_startrelay[i] -1);
Shutter.real_position[i] = ShutterPercentToRealPosition(Settings.shutter_position[i], i);
//Shutter.real_position[i] = Settings.shutter_position[i] <= 5 ? Settings.shuttercoeff[2][i] * Settings.shutter_position[i] : Settings.shuttercoeff[1][i] * Settings.shutter_position[i] + Settings.shuttercoeff[0,i];
Shutter.start_position[i] = Shutter.target_position[i] = Shutter.real_position[i];
2019-10-30 08:28:46 +00:00
Shutter.motordelay[i] = Settings.shutter_motordelay[i];
char shutter_open_chr[10];
dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr);
char shutter_close_chr[10];
dtostrfd((float)Shutter.close_time[i] / 10, 1, shutter_close_chr);
2020-03-10 07:41:37 +00:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Shutter %d (Relay:%d): Init. Pos: %d [%d %%], Open Vel.: 100, Close Vel.: %d , Max Way: %d, Opentime %s [s], Closetime %s [s], CoeffCalc: c0: %d, c1 %d, c2: %d, c3: %d, c4: %d, binmask %d, is inverted %d, is locked %d, end stop time enabled %d, webButtons inverted %d, shuttermode %d, motordelay %d"),
2019-12-12 07:39:44 +00:00
i+1, Settings.shutter_startrelay[i], Shutter.real_position[i], Settings.shutter_position[i], Shutter.close_velocity[i], Shutter.open_max[i], shutter_open_chr, shutter_close_chr,
Settings.shuttercoeff[0][i], Settings.shuttercoeff[1][i], Settings.shuttercoeff[2][i], Settings.shuttercoeff[3][i], Settings.shuttercoeff[4][i],
2020-03-10 07:41:37 +00:00
Shutter.mask, (Settings.shutter_options[i]&1) ? 1 : 0, (Settings.shutter_options[i]&2) ? 1 : 0, (Settings.shutter_options[i]&4) ? 1 : 0, (Settings.shutter_options[i]&8) ? 1 : 0, Shutter.mode, Shutter.motordelay[i]);
} else {
// terminate loop at first INVALID shutter.
break;
}
2020-01-22 12:23:59 +00:00
ShutterLimitRealAndTargetPositions(i);
Settings.shutter_accuracy = 1;
}
}
2020-01-04 14:09:57 +00:00
void ShutterReportPosition(bool always)
{
Response_P(PSTR("{"));
rules_flag.shutter_moving = 0;
2020-01-04 14:09:57 +00:00
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]);
2020-01-04 14:09:57 +00:00
uint32_t position = ShutterRealToPercentPosition(Shutter.real_position[i], i);
if (Shutter.direction[i] != 0) {
rules_flag.shutter_moving = 1;
2020-01-04 14:09:57 +00:00
ShutterLogPos(i);
}
2020-01-04 13:20:41 +00:00
if (i) { ResponseAppend_P(PSTR(",")); }
uint32_t target = ShutterRealToPercentPosition(Shutter.target_position[i], i);
ResponseAppend_P(JSON_SHUTTER_POS, i+1, (Settings.shutter_options[i] & 1) ? 100-position : position, Shutter.direction[i],(Settings.shutter_options[i] & 1) ? 100-target : target );
}
ResponseJsonEnd();
if (always || (rules_flag.shutter_moving)) {
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER));
//XdrvRulesProcess(); //removed because to many exceptions and reboots.
}
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), rules_flag.shutter_moving, rules_flag.shutter_moved);
}
2020-01-13 11:00:34 +00:00
void ShutterLimitRealAndTargetPositions(uint32_t i) {
if (Shutter.real_position[i]<0) Shutter.real_position[i] = 0;
if (Shutter.real_position[i]>Shutter.open_max[i]) Shutter.real_position[i] = Shutter.open_max[i];
if (Shutter.target_position[i]<0) Shutter.target_position[i] = 0;
if (Shutter.target_position[i]>Shutter.open_max[i]) Shutter.target_position[i] = Shutter.open_max[i];
}
void ShutterUpdatePosition(void)
{
char scommand[CMDSZ];
char stopic[TOPSZ];
for (uint32_t i = 0; i < shutters_present; i++) {
if (Shutter.direction[i] != 0) {
int32_t stop_position_delta = 20;
if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) {
// Calculate position with counter. Much more accurate and no need for motordelay workaround
// adding some steps to stop early
Shutter.real_position[i] = ShutterCounterBasedPosition(i);
if (!Shutter.start_reported) {
ShutterReportPosition(true);
XdrvRulesProcess();
Shutter.start_reported = 1;
}
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[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[i] / max_frequency * Shutter.direction[i] ;
int32_t next_possible_stop = Shutter.real_position[i] + minstopway ;
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[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]- (100 * Shutter.direction[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*11/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[i] == max_frequency) {
Shutter.accelerator[i] = 0;
}
} else {
Shutter.real_position[i] = Shutter.start_position[i] + ( (Shutter.time[i] - Shutter.motordelay[i]) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i]));
}
if ( Shutter.real_position[i] * Shutter.direction[i] + stop_position_delta >= Shutter.target_position[i] * Shutter.direction[i] ) {
// calculate relay number responsible for current movement.
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Stop Condition detected: real: %d, Target: %d, direction: %d"),Shutter.real_position[i], Shutter.target_position[i],Shutter.direction[i]);
uint8_t cur_relay = Settings.shutter_startrelay[i] + (Shutter.direction[i] == 1 ? 0 : 1) ;
int16_t missing_steps;
switch (Shutter.mode) {
case SHT_PULSE_OPEN__PULSE_CLOSE:
// we have a momentary switch here. Needs additional pulse on same relay after the end
if (SRC_PULSETIMER == last_source || SRC_SHUTTER == last_source || SRC_WEBGUI == last_source) {
ExecuteCommandPower(cur_relay, 1, SRC_SHUTTER);
} else {
last_source = SRC_SHUTTER;
}
break;
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[i]);
Shutter.accelerator[i] = 0;
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[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);
}
analogWrite(pin[GPIO_PWM1+i], 0);
Shutter.real_position[i] = ShutterCounterBasedPosition(i);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Real %d, pulsecount %d, start %d"), Shutter.real_position[i],RtcSettings.pulse_counter[i], Shutter.start_position[i]);
if ((1 << (Settings.shutter_startrelay[i]-1)) & power) {
ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER);
ExecuteCommandPower(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER);
}
break;
case SHT_OFF_ON__OPEN_CLOSE:
if ((1 << (Settings.shutter_startrelay[i]-1)) & power) {
ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER);
ExecuteCommandPower(Settings.shutter_startrelay[i]+1, 0, SRC_SHUTTER);
}
break;
case SHT_OFF_OPEN__OFF_CLOSE:
// avoid switching OFF a relay already OFF
if ((1 << (cur_relay-1)) & power) {
// Relay is on and need to be switched off.
ExecuteCommandPower(cur_relay, 0, SRC_SHUTTER);
}
break;
}
2020-01-13 11:00:34 +00:00
ShutterLimitRealAndTargetPositions(i);
Settings.shutter_position[i] = ShutterRealToPercentPosition(Shutter.real_position[i], i);
2020-01-04 14:09:57 +00:00
ShutterLogPos(i);
Shutter.start_position[i] = Shutter.real_position[i];
// sending MQTT result to broker
snprintf_P(scommand, sizeof(scommand),PSTR(D_SHUTTER "%d"), i+1);
GetTopic_P(stopic, STAT, mqtt_topic, scommand);
Response_P("%d", (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]);
MqttPublish(stopic, Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN
Shutter.direction[i] = 0;
ShutterReportPosition(true);
rules_flag.shutter_moved = 1;
XdrvRulesProcess();
}
}
}
}
2020-01-04 14:09:57 +00:00
bool ShutterState(uint32_t device)
{
device--;
device &= 3;
2019-11-03 12:51:22 +00:00
return (Settings.flag3.shutter_mode && // SetOption80 - Enable shutter support
(Shutter.mask & (1 << (Settings.shutter_startrelay[device]-1))) );
}
2020-01-04 14:09:57 +00:00
void ShutterStartInit(uint32_t i, int32_t direction, int32_t target_pos)
{
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: dir %d, delta1 %d, delta2 %d, grant %d"),direction, (Shutter.open_max[i] - Shutter.real_position[i]) / Shutter.close_velocity[i], Shutter.real_position[i] / Shutter.close_velocity[i], 2+Shutter.motordelay[i]);
2020-01-04 14:09:57 +00:00
if ( ( (1 == direction) && ((Shutter.open_max[i] - Shutter.real_position[i]) / 100 <= 2) )
|| ( (-1 == direction) && (Shutter.real_position[i] / Shutter.close_velocity[i] <= 2)) ) {
Shutter.skip_relay_change = 1;
} else {
if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) {
Shutter.pwm_frequency[i] = 0;
analogWriteFreq(Shutter.pwm_frequency[i]);
analogWrite(pin[GPIO_PWM1+i], 0);
RtcSettings.pulse_counter[i] = 0;
Shutter.accelerator[i] = Shutter.max_pwm_frequency / (Shutter.motordelay[i]>0 ? Shutter.motordelay[i] : 1);
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Ramp up: %d"), Shutter.accelerator[i]);
}
Shutter.target_position[i] = target_pos;
Shutter.start_position[i] = Shutter.real_position[i];
Shutter.time[i] = 0;
Shutter.skip_relay_change = 0;
Shutter.direction[i] = direction;
rules_flag.shutter_moving = 1;
rules_flag.shutter_moved = 0;
Shutter.start_reported = 0;
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: real %d, start %d, counter %d, max_freq %d, dir %d, freq %d"),Shutter.real_position[i], Shutter.start_position[i] ,RtcSettings.pulse_counter[i],Shutter.max_pwm_frequency , Shutter.direction[i] ,Shutter.max_pwm_frequency );
}
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start shutter: %d from %d to %d in directin %d"), i, Shutter.start_position[i], Shutter.target_position[i], Shutter.direction[i]);
}
2020-01-04 14:09:57 +00:00
void ShutterWaitForMotorStop(uint32_t i)
{
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Wait for Motorstop.."));
2020-01-04 14:09:57 +00:00
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[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);
}
analogWrite(pin[GPIO_PWM1+i], 0);
Shutter.real_position[i] = ShutterCounterBasedPosition(i);
} else {
ExecuteCommandPower(Settings.shutter_startrelay[i], 0, SRC_SHUTTER);
delay(MOTOR_STOP_TIME);
}
} else {
delay(MOTOR_STOP_TIME);
}
}
2020-01-04 14:09:57 +00:00
int32_t ShutterCounterBasedPosition(uint32_t i)
{
return ((int32_t)RtcSettings.pulse_counter[i]*Shutter.direction[i]*2000 / Shutter.max_pwm_frequency)+Shutter.start_position[i];
}
void ShutterRelayChanged(void)
{
// Shutter.switched_relay = binary relay that was recently changed and cause an Action
// powerstate_local = binary powermatrix and relays from shutter: 0..3
// relays_changed = bool if one of the relays that belong to the shutter changed not by shutter or pulsetimer
char stemp1[10];
for (uint32_t i = 0; i < shutters_present; i++) {
power_t powerstate_local = (power >> (Settings.shutter_startrelay[i] -1)) & 3;
//uint8 manual_relays_changed = ((Shutter.switched_relay >> (Settings.shutter_startrelay[i] -1)) & 3) && SRC_IGNORE != last_source && SRC_SHUTTER != last_source && SRC_PULSETIMER != last_source ;
uint8 manual_relays_changed = ((Shutter.switched_relay >> (Settings.shutter_startrelay[i] -1)) & 3) && SRC_SHUTTER != last_source && SRC_PULSETIMER != last_source ;
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: source: %s, powerstate_local %ld, Shutter.switched_relay %d, manual change %d"), i+1, GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource), powerstate_local,Shutter.switched_relay,manual_relays_changed);
if (manual_relays_changed) {
//Shutter.skip_relay_change = true;
2020-01-13 11:00:34 +00:00
ShutterLimitRealAndTargetPositions(i);
if (Shutter.mode == SHT_OFF_ON__OPEN_CLOSE || Shutter.mode == SHT_OFF_ON__OPEN_CLOSE_STEPPER) {
ShutterWaitForMotorStop(i);
switch (powerstate_local) {
case 1:
ShutterStartInit(i, 1, Shutter.open_max[i]);
break;
case 3:
ShutterStartInit(i, -1, 0);
break;
default:
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: Switch OFF motor."),i);
Shutter.target_position[i] = Shutter.real_position[i];
}
} else {
if (Shutter.direction[i] != 0 && (!powerstate_local || (powerstate_local && Shutter.mode == SHT_PULSE_OPEN__PULSE_CLOSE))) {
Shutter.target_position[i] = Shutter.real_position[i];
2019-12-12 07:39:44 +00:00
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: Switch OFF motor. Target: %ld, source: %s, powerstate_local %ld, Shutter.switched_relay %d, manual change %d"), i+1, Shutter.target_position[i], GetTextIndexed(stemp1, sizeof(stemp1), last_source, kCommandSource), powerstate_local,Shutter.switched_relay,manual_relays_changed);
} else {
last_source = SRC_SHUTTER; // avoid switch off in the next loop
if (powerstate_local == 2) { // testing on CLOSE relay, if ON
// close with relay two
ShutterWaitForMotorStop(i);
ShutterStartInit(i, -1, 0);
} else {
// opens with relay one
ShutterWaitForMotorStop(i);
ShutterStartInit(i, 1, Shutter.open_max[i]);
}
}
2019-12-12 07:39:44 +00:00
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Shutter %d: Target: %ld, powerstatelocal %d"), i+1, Shutter.target_position[i], powerstate_local);
}
}
}
}
bool ShutterButtonIsSimultaneousHold(uint32_t button_index, uint32_t shutter_index) {
// check for simultaneous shutter button hold
uint32 min_shutterbutton_hold_timer = -1; // -1 == max(uint32)
for (uint32_t i = 0; i < MAX_KEYS; i++) {
if ((button_index != i) && (Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (Button.hold_timer[i] < min_shutterbutton_hold_timer))
min_shutterbutton_hold_timer = Button.hold_timer[i];
}
return ((-1 != min_shutterbutton_hold_timer) && (min_shutterbutton_hold_timer > (Button.hold_timer[button_index]>>1)));
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
void ShutterButtonHandler(void)
{
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;
uint16_t loops_per_second = 1000 / Settings.button_debounce; // ButtonDebounce (50)
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
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;
press_index = 1;
} else {
if ((Shutter.direction[shutter_index]) && (Button.press_counter[button_index]==0)) {
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 {
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
Button.press_counter[button_index] = (Button.window_timer[button_index]) ? Button.press_counter[button_index] +1 : 1;
// Button.window_timer[button_index] = (Button.press_counter[button_index]==1) ? loops_per_second / 2 : loops_per_second; // 0.5 second multi press window after 1st press, 1s afterwards
2020-03-10 07:41:37 +00:00
Button.window_timer[button_index] = (loops_per_second >> 2) * 3; // 0.75 second multi press window
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
blinks = 201;
}
if (NOT_PRESSED == button) {
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 (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
}
}
if ((Button.press_counter[button_index]<99) && (Button.hold_timer[button_index] == loops_per_second * Settings.param[P_HOLD_TIME] / 10)) { // press still valid && SetOption32 (40) - Button hold
2020-01-22 12:23:59 +00:00
// check for simultaneous shutter button hold
if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) {
2020-01-22 12:23:59 +00:00
// simultaneous shutter button hold detected
for (uint32_t i = 0; i < MAX_KEYS; i++)
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index))
2020-01-22 12:23:59 +00:00
Button.press_counter[i] = 99; // Remember to discard further action for press & hold within button timings
press_index = 0;
buttonState = SHT_PRESSED_HOLD_SIMULTANEOUS;
}
2020-01-22 12:23:59 +00:00
if (Button.press_counter[button_index]<99) {
press_index = 0;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
buttonState = SHT_PRESSED_HOLD;
2020-01-22 12:23:59 +00:00
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
Button.press_counter[button_index] = 0;
}
2020-01-22 12:23:59 +00:00
if ((Button.press_counter[button_index]==0) && (Button.hold_timer[button_index] == loops_per_second * IMMINENT_RESET_FACTOR * Settings.param[P_HOLD_TIME] / 10)) { // SetOption32 (40) - Button held for factor times longer
press_index = -1;
// check for simultaneous shutter button extend hold
if (ShutterButtonIsSimultaneousHold(button_index, shutter_index)) {
// simultaneous shutter button extend hold detected
buttonState = SHT_PRESSED_EXT_HOLD_SIMULTANEOUS;
} else {
buttonState = SHT_PRESSED_EXT_HOLD;
}
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
}
if (!Settings.flag.button_single) { // SetOption13 (0) - Allow multi-press
if (Button.window_timer[button_index]) {
Button.window_timer[button_index]--;
} else {
if (!restart_flag && !Button.hold_timer[button_index] && (Button.press_counter[button_index] > 0)) {
if (Button.press_counter[button_index]<99) {
2020-01-22 12:23:59 +00:00
// check for simultaneous shutter button press
uint32 min_shutterbutton_press_counter = -1; // -1 == max(uint32)
2020-01-22 12:23:59 +00:00
for (uint32_t i = 0; i < MAX_KEYS; i++) {
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, i %d"), Settings.shutter_button[i], shutter_index, Button.press_counter[i] , min_shutterbutton_press_counter, i);
if ((button_index != i) && (Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index) && (i != button_index) && (Button.press_counter[i] < min_shutterbutton_press_counter)) {
2020-01-22 12:23:59 +00:00
min_shutterbutton_press_counter = Button.press_counter[i];
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: min_shutterbutton_press_counter %d"), min_shutterbutton_press_counter);
}
2020-01-22 12:23:59 +00:00
}
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"));
2020-01-22 12:23:59 +00:00
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))
2020-01-22 12:23:59 +00:00
Button.press_counter[i] = 99; // Remember to discard further action for press & hold within button timings
buttonState = SHT_PRESSED_MULTI_SIMULTANEOUS;
}
2020-01-22 12:23:59 +00:00
if ((buttonState != SHT_PRESSED_MULTI_SIMULTANEOUS) && (Button.press_counter[button_index]<99)) {
// no simultaneous shutter button press >3 detected
2020-01-22 12:23:59 +00:00
press_index = Button.press_counter[button_index];
buttonState = SHT_PRESSED_MULTI;
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
Button.press_counter[button_index] = 0;
}
}
}
if (buttonState != SHT_NOT_PRESSED) {
if ((!Settings.flag.button_restrict) && (((press_index>=5) && (press_index<=7)) || (buttonState == SHT_PRESSED_EXT_HOLD) || (buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS))){
// check number of buttons for this shutter
uint8_t shutter_index_num_buttons = 0;
for (uint32_t i = 0; i < MAX_KEYS; i++) {
if ((Settings.shutter_button[i] & (1<<31)) && ((Settings.shutter_button[i] & 0x03) == shutter_index)) {
shutter_index_num_buttons++;
}
}
if ((buttonState == SHT_PRESSED_MULTI_SIMULTANEOUS) || ((shutter_index_num_buttons==1) && (buttonState == SHT_PRESSED_MULTI))){
// 5x..7x && no SetOption1 (0) checked above
// simultaneous or stand alone button press 5x, 6x, 7x detected
char scmnd[20];
GetTextIndexed(scmnd, sizeof(scmnd), press_index -3, kCommands);
ExecuteCommand(scmnd, SRC_BUTTON);
return;
} else if ((buttonState == SHT_PRESSED_EXT_HOLD_SIMULTANEOUS) || ((shutter_index_num_buttons==1) && (buttonState == SHT_PRESSED_EXT_HOLD))){
// no SetOption1 (0) checked above
// simultaneous or stand alone button extended hold detected
char scmnd[20];
snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_RESET " 1"));
ExecuteCommand(scmnd, SRC_BUTTON);
return;
}
}
if (buttonState <= SHT_PRESSED_IMMEDIATE) {
2020-01-22 12:23:59 +00:00
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;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: shutter %d, button %d = %d (single=1, double=2, tripple=3, hold=4)"), shutter_index+1, button_index+1, pos_press_index+1);
XdrvMailbox.index = shutter_index +1;
last_source = SRC_BUTTON;
XdrvMailbox.data_len = 0;
char databuf[1] = "";
XdrvMailbox.data = databuf;
XdrvMailbox.command = NULL;
if (buttonState == SHT_PRESSED_IMMEDIATE) {
XdrvMailbox.payload = XdrvMailbox.index;
CmndShutterStop();
} else {
2020-01-22 12:23:59 +00:00
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;
CmndShutterStop();
} else {
XdrvMailbox.payload = position = (position-1)<<1;
CmndShutterPosition();
if (Settings.shutter_button[button_index] & ((0x01<<26)<<pos_press_index)) {
// MQTT broadcast to grouptopic
char scommand[CMDSZ];
char stopic[TOPSZ];
for (uint32_t i = 0; i < MAX_SHUTTERS; i++) {
if ((i==shutter_index) || (Settings.shutter_button[button_index] & (0x01<<30))) {
snprintf_P(scommand, sizeof(scommand),PSTR("ShutterPosition%d"), i+1);
GetGroupTopic_P(stopic, scommand);
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]
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
2020-01-22 12:23:59 +00:00
Response_P(PSTR("{"));
ResponseAppend_P(JSON_SHUTTER_BUTTON, shutter_index+1, (buttonState <= SHT_PRESSED_EXT_HOLD) ? (button_index+1) : 0, press_index);
2020-01-22 12:23:59 +00:00
ResponseJsonEnd();
MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER));
XdrvRulesProcess();
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
}
2020-01-04 14:09:57 +00:00
void ShutterSetPosition(uint32_t device, uint32_t position)
{
char svalue[32]; // Command and number parameter
snprintf_P(svalue, sizeof(svalue), PSTR(D_PRFX_SHUTTER D_CMND_SHUTTER_POSITION "%d %d"), device, position);
ExecuteCommand(svalue, SRC_IGNORE);
}
/*********************************************************************************************\
* Commands
\*********************************************************************************************/
void CmndShutterOpen(void)
{
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Payload close: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.i);
2020-01-04 14:09:57 +00:00
if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) {
XdrvMailbox.index = XdrvMailbox.payload;
}
XdrvMailbox.payload = 100;
last_source = SRC_WEBGUI;
CmndShutterPosition();
}
void CmndShutterClose(void)
{
//AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Payload open: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.i);
2020-01-04 14:09:57 +00:00
if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) {
XdrvMailbox.index = XdrvMailbox.payload;
}
XdrvMailbox.payload = 0;
XdrvMailbox.data_len = 0;
last_source = SRC_WEBGUI;
CmndShutterPosition();
}
void CmndShutterStop(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) {
if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) {
XdrvMailbox.index = XdrvMailbox.payload;
}
uint32_t i = XdrvMailbox.index -1;
if (Shutter.direction[i] != 0) {
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Stop moving %d: dir: %d"), XdrvMailbox.index, Shutter.direction[i]);
// set stop position 10 steps ahead (0.5sec to allow normal stop)
int32_t temp_realpos = Shutter.start_position[i] + ( (Shutter.time[i]+10) * (Shutter.direction[i] > 0 ? 100 : -Shutter.close_velocity[i]));
XdrvMailbox.payload = ShutterRealToPercentPosition(temp_realpos, i);
//XdrvMailbox.payload = Settings.shuttercoeff[2][i] * 5 > temp_realpos ? temp_realpos / Settings.shuttercoeff[2][i] : (temp_realpos-Settings.shuttercoeff[0,i]) / Settings.shuttercoeff[1][i];
last_source = SRC_WEBGUI;
CmndShutterPosition();
} else {
if (XdrvMailbox.command)
ResponseCmndDone();
}
} else {
if (XdrvMailbox.command)
ResponseCmndIdxChar("Locked");
}
}
}
void CmndShutterPosition(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (!(Settings.shutter_options[XdrvMailbox.index-1] & 2)) {
uint32_t index = XdrvMailbox.index-1;
//limit the payload
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))) {
CmndShutterOpen();
return;
}
if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_DOWN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_CLOSE) || ((Shutter.direction[index]==0) && !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDOWN))) {
CmndShutterClose();
return;
}
if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP) || ((Shutter.direction[index]) && (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEUP) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDOWN)))) {
XdrvMailbox.payload = -99;
CmndShutterStop();
return;
}
}
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.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);
}
if ( (target_pos_percent >= 0) && (target_pos_percent <= 100) && abs(Shutter.target_position[index] - Shutter.real_position[index] ) / Shutter.close_velocity[index] > 2) {
if (Settings.shutter_options[index] & 4) {
if (0 == target_pos_percent) Shutter.target_position[index] -= 1 * 2000;
if (100 == target_pos_percent) Shutter.target_position[index] += 1 * 2000;
}
int8_t new_shutterdirection = Shutter.real_position[index] < Shutter.target_position[index] ? 1 : -1;
if (Shutter.direction[index] == -new_shutterdirection) {
// direction need to be changed. on momentary switches first stop the Shutter
if (SHT_PULSE_OPEN__PULSE_CLOSE == Shutter.mode) {
// code for momentary shutters only small switch on to stop Shutter
ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 0 : 1), 1, SRC_SHUTTER);
delay(100);
} else {
if (SHT_OFF_OPEN__OFF_CLOSE == Shutter.mode) {
ExecuteCommandPower(Settings.shutter_startrelay[index] + ((new_shutterdirection == 1) ? 1 : 0), 0, SRC_SHUTTER);
ShutterWaitForMotorStop(index);
}
}
}
if (Shutter.direction[index] != new_shutterdirection) {
if ((SHT_OFF_ON__OPEN_CLOSE == Shutter.mode) || (SHT_OFF_ON__OPEN_CLOSE_STEPPER == Shutter.mode)) {
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay5 5s, xdrv %d"), XdrvMailbox.payload);
ShutterWaitForMotorStop(index);
ExecuteCommandPower(Settings.shutter_startrelay[index], 0, SRC_SHUTTER);
ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]);
if (Shutter.skip_relay_change == 0) {
// Code for shutters with circuit safe configuration, switch the direction Relay
ExecuteCommandPower(Settings.shutter_startrelay[index] +1, new_shutterdirection == 1 ? 0 : 1, SRC_SHUTTER);
// power on
ExecuteCommandPower(Settings.shutter_startrelay[index], 1, SRC_SHUTTER);
}
} else {
// now start the motor for the right direction, work for momentary and normal shutters.
AddLog_P2(LOG_LEVEL_INFO, PSTR("SHT: Start in dir %d"), Shutter.direction[index]);
ShutterStartInit(index, new_shutterdirection, Shutter.target_position[index]);
if (Shutter.skip_relay_change == 0) {
ExecuteCommandPower(Settings.shutter_startrelay[index] + (new_shutterdirection == 1 ? 0 : 1), 1, SRC_SHUTTER);
}
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Delay6 5s, xdrv %d"), XdrvMailbox.payload);
}
Shutter.switched_relay = 0;
}
} else {
target_pos_percent = ShutterRealToPercentPosition(Shutter.real_position[index], index);
ShutterReportPosition(true);
}
XdrvMailbox.index = index +1; // Fix random index for ShutterClose
if (XdrvMailbox.command)
ResponseCmndIdxNumber((Settings.shutter_options[index] & 1) ? 100 - target_pos_percent : target_pos_percent);
} else {
ShutterReportPosition(true);
if (XdrvMailbox.command)
ResponseCmndIdxChar("Locked");
}
}
}
void CmndShutterOpenTime(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.data_len > 0) {
Settings.shutter_opentime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
ShutterInit();
}
char time_chr[10];
dtostrfd((float)(Settings.shutter_opentime[XdrvMailbox.index -1]) / 10, 1, time_chr);
ResponseCmndIdxChar(time_chr);
}
}
void CmndShutterCloseTime(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.data_len > 0) {
Settings.shutter_closetime[XdrvMailbox.index -1] = (uint16_t)(10 * CharToFloat(XdrvMailbox.data));
ShutterInit();
}
char time_chr[10];
dtostrfd((float)(Settings.shutter_closetime[XdrvMailbox.index -1]) / 10, 1, time_chr);
ResponseCmndIdxChar(time_chr);
}
}
2019-10-30 08:28:46 +00:00
void CmndShutterMotorDelay(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.data_len > 0) {
Settings.shutter_motordelay[XdrvMailbox.index -1] = (uint16_t)(steps_per_second * CharToFloat(XdrvMailbox.data));
2019-10-30 08:28:46 +00:00
ShutterInit();
}
char time_chr[10];
dtostrfd((float)(Settings.shutter_motordelay[XdrvMailbox.index -1]) / steps_per_second, 2, time_chr);
2019-10-30 08:28:46 +00:00
ResponseCmndIdxChar(time_chr);
}
}
void CmndShutterRelay(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 64)) {
Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload;
if (XdrvMailbox.payload > 0) {
Shutter.mask |= 3 << (XdrvMailbox.payload - 1);
} else {
Shutter.mask ^= 3 << (Settings.shutter_startrelay[XdrvMailbox.index -1] - 1);
}
Settings.shutter_startrelay[XdrvMailbox.index -1] = XdrvMailbox.payload;
ShutterInit();
// if payload is 0 to disable the relay there must be a reboot. Otherwhise does not work
}
ResponseCmndIdxNumber(Settings.shutter_startrelay[XdrvMailbox.index -1]);
}
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
void CmndShutterButton(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_SHUTTERS)) {
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
uint32_t setting = 0;
// (setting>>31)&(0x01) : enabled
// (setting>>30)&(0x01) : mqtt broadcast to all index
// (setting>>29)&(0x01) : mqtt broadcast hold
// (setting>>28)&(0x01) : mqtt broadcast tripple press
// (setting>>27)&(0x01) : mqtt broadcast double press
// (setting>>26)&(0x01) : mqtt broadcast single press
// (setting>>20)&(0x3f) : shutter_position hold; 0 disabled, 1..101 == 0..100%
// (setting>>14)&(0x3f) : shutter_position tripple press 0 disabled, 1..101 == 0..100%
// (setting>> 8)&(0x3f) : shutter_position double press 0 disabled, 1..101 == 0..100%
// (setting>> 2)&(0x3f) : shutter_position single press 0 disabled, 1..101 == 0..100%
// (setting>> 0)&(0x03) : shutter_index
if (XdrvMailbox.data_len > 0) {
2020-01-09 10:35:01 +00:00
uint32_t i = 0;
uint32_t button_index = 0;
bool done = false;
bool isShortCommand = false;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
char *str_ptr;
2020-01-09 10:35:01 +00:00
char data_copy[strlen(XdrvMailbox.data) +1];
strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it.
// Loop through the data string, splitting on ' ' seperators.
for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < (1+4+4+1); str = strtok_r(nullptr, " ", &str_ptr), i++) {
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
int field;
2020-01-09 10:35:01 +00:00
if (str[0] == '-') {
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
field = -1;
2020-01-09 10:35:01 +00:00
} else {
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
field = atoi(str);
2020-01-09 10:35:01 +00:00
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
switch (i) {
case 0:
if ((field >= -1) && (field<=4)) {
button_index = (field<=0)?(-1):field;
done = (button_index==-1);
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
} else
done = true;
break;
case 1:
if (!strcmp_P(str, PSTR("up"))) {
setting |= (((100>>1)+1)<<2) | (((50>>1)+1)<<8) | (((75>>1)+1)<<14) | (((100>>1)+1)<<20);
isShortCommand = true;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
break;
} else if (!strcmp_P(str, PSTR("down"))) {
setting |= (((0>>1)+1)<<2) | (((50>>1)+1)<<8) | (((25>>1)+1)<<14) | (((0>>1)+1)<<20);
isShortCommand = true;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
break;
} else if (!strcmp_P(str, PSTR("updown"))) {
setting |= (((100>>1)+1)<<2) | (((0>>1)+1)<<8) | (((50>>1)+1)<<14);
isShortCommand = true;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
break;
}
case 2:
if (isShortCommand) {
if ((field==1) && (setting & (0x3F<<(2+6*3))))
// if short command up or down then also enable MQTT broadcast
setting |= (0x3<<29);
done = true;
break;
}
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
case 3:
case 4:
if ((field >= -1) && (field<=100))
setting |= (((field>>1)+1)<<(i*6 + (2-6)));
break;
case 5:
case 6:
case 7:
case 8:
case 9:
if (field==1)
setting |= (1<<(i + (26-5)));
break;
}
if (done) break;
}
if (button_index) {
if (button_index==-1) {
// remove all buttons for this shutter
for (uint32_t i=0 ; i < MAX_KEYS ; i++)
if ((Settings.shutter_button[i]&0x3) == (XdrvMailbox.index-1))
Settings.shutter_button[i] = 0;
} else {
if (setting) {
// anything was set
setting |= (1<<31);
setting |= (XdrvMailbox.index-1) & 0x3;
}
Settings.shutter_button[button_index-1] = setting;
}
}
}
char setting_chr[30*MAX_KEYS] = "-", *setting_chr_ptr = setting_chr;
for (uint32_t i=0 ; i < MAX_KEYS ; i++) {
setting = Settings.shutter_button[i];
if ((setting&(1<<31)) && ((setting&0x3) == (XdrvMailbox.index-1))) {
if (*setting_chr_ptr == 0)
setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR("|"));
setting_chr_ptr += snprintf_P(setting_chr_ptr, 2, PSTR("%d"), i+1);
for (uint32_t j=0 ; j < 4 ; j++) {
int8_t pos = (((setting>> (2+6*j))&(0x3f))-1)<<1;
if (pos>=0)
setting_chr_ptr += snprintf_P(setting_chr_ptr, 5, PSTR(" %d"), pos);
else
setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -"));
}
for (uint32_t j=0 ; j < 5 ; j++) {
bool mqtt = ((setting>>(26+j))&(0x01)!=0);
if (mqtt)
setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" 1"));
else
setting_chr_ptr += sprintf_P(setting_chr_ptr, PSTR(" -"));
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
}
}
ResponseCmndIdxChar(setting_chr);
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
}
}
void CmndShutterSetHalfway(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 100)) {
Settings.shutter_set50percent[XdrvMailbox.index -1] = (Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - XdrvMailbox.payload : XdrvMailbox.payload;
ShutterInit();
}
ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 100 - Settings.shutter_set50percent[XdrvMailbox.index -1] : Settings.shutter_set50percent[XdrvMailbox.index -1]);
}
}
void CmndShutterFrequency(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 20000)) {
Shutter.max_pwm_frequency = XdrvMailbox.payload;
if (shutters_present < 4) {
Settings.shuttercoeff[4][3] = Shutter.max_pwm_frequency;
}
ShutterInit();
ResponseCmndNumber(XdrvMailbox.payload); // ????
} else {
ResponseCmndNumber(Shutter.max_pwm_frequency);
}
}
void CmndShutterSetClose(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
Shutter.real_position[XdrvMailbox.index -1] = 0;
ShutterStartInit(XdrvMailbox.index -1, 0, 0);
Settings.shutter_position[XdrvMailbox.index -1] = 0;
ResponseCmndIdxChar(D_CONFIGURATION_RESET);
}
}
void CmndShutterInvert(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.payload == 0) {
Settings.shutter_options[XdrvMailbox.index -1] &= ~(1);
} else if (XdrvMailbox.payload == 1) {
Settings.shutter_options[XdrvMailbox.index -1] |= (1);
}
ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 1) ? 1 : 0);
}
}
2020-01-09 10:35:01 +00:00
void CmndShutterCalibration(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.data_len > 0) {
2020-01-09 10:35:01 +00:00
uint32_t i = 0;
char *str_ptr;
char data_copy[strlen(XdrvMailbox.data) +1];
strncpy(data_copy, XdrvMailbox.data, sizeof(data_copy)); // Duplicate data as strtok_r will modify it.
// Loop through the data string, splitting on ' ' seperators.
for (char *str = strtok_r(data_copy, " ", &str_ptr); str && i < 5; str = strtok_r(nullptr, " ", &str_ptr), i++) {
int field = atoi(str);
// The fields in a data string can only range from 1-30000.
// and following value must be higher than previous one
if ((field <= 0) || (field > 30000) || ( (i>0) && (field <= messwerte[i-1]) ) ) {
break;
}
2020-01-09 10:35:01 +00:00
messwerte[i] = field;
}
for (i = 0; i < 5; i++) {
Settings.shuttercoeff[i][XdrvMailbox.index -1] = SHT_DIV_ROUND((uint32_t)messwerte[i] * 1000, messwerte[4]);
2020-01-09 10:35:01 +00:00
AddLog_P2(LOG_LEVEL_INFO, PSTR("Settings.shuttercoeff: %d, i: %d, value: %d, messwert %d"), i,XdrvMailbox.index -1,Settings.shuttercoeff[i][XdrvMailbox.index -1], messwerte[i]);
}
ShutterInit();
ResponseCmndIdxChar(XdrvMailbox.data);
} else {
char setting_chr[30] = "0";
snprintf_P(setting_chr, sizeof(setting_chr), PSTR("%d %d %d %d %d"), Settings.shuttercoeff[0][XdrvMailbox.index -1], Settings.shuttercoeff[1][XdrvMailbox.index -1], Settings.shuttercoeff[2][XdrvMailbox.index -1], Settings.shuttercoeff[3][XdrvMailbox.index -1], Settings.shuttercoeff[4][XdrvMailbox.index -1]);
ResponseCmndIdxChar(setting_chr);
}
}
}
void CmndShutterLock(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.payload == 0) {
Settings.shutter_options[XdrvMailbox.index -1] &= ~(2);
} else if (XdrvMailbox.payload == 1) {
Settings.shutter_options[XdrvMailbox.index -1] |= (2);
}
ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 2) ? 1 : 0);
}
}
2020-01-13 11:00:34 +00:00
void CmndShutterEnableEndStopTime(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.payload == 0) {
Settings.shutter_options[XdrvMailbox.index -1] &= ~(4);
} else if (XdrvMailbox.payload == 1) {
Settings.shutter_options[XdrvMailbox.index -1] |= (4);
}
ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 4) ? 1 : 0);
}
}
2020-03-10 07:41:37 +00:00
void CmndShutterInvertWebButtons(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) {
if (XdrvMailbox.payload == 0) {
Settings.shutter_options[XdrvMailbox.index -1] &= ~(8);
} else if (XdrvMailbox.payload == 1) {
Settings.shutter_options[XdrvMailbox.index -1] |= (8);
}
ResponseCmndIdxNumber((Settings.shutter_options[XdrvMailbox.index -1] & 8) ? 1 : 0);
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xdrv27(uint8_t function)
{
bool result = false;
2019-11-03 12:51:22 +00:00
if (Settings.flag3.shutter_mode) { // SetOption80 - Enable shutter support
switch (function) {
case FUNC_PRE_INIT:
ShutterInit();
break;
case FUNC_EVERY_50_MSECOND:
ShutterUpdatePosition();
break;
case FUNC_EVERY_SECOND:
//case FUNC_EVERY_250_MSECOND:
2020-01-04 14:09:57 +00:00
ShutterReportPosition(false);
break;
case FUNC_COMMAND:
result = DecodeCommand(kShutterCommands, ShutterCommand);
break;
case FUNC_JSON_APPEND:
for (uint8_t i = 0; i < shutters_present; i++) {
uint8_t position = (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i] : Settings.shutter_position[i];
uint8_t target = (Settings.shutter_options[i] & 1) ? 100 - ShutterRealToPercentPosition(Shutter.target_position[i], i) : ShutterRealToPercentPosition(Shutter.target_position[i], i);
ResponseAppend_P(",");
ResponseAppend_P(JSON_SHUTTER_POS, i+1, position, Shutter.direction[i],target);
#ifdef USE_DOMOTICZ
if ((0 == tele_period) && (0 == i)) {
DomoticzSensor(DZ_SHUTTER, position);
}
#endif // USE_DOMOTICZ
}
break;
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 = 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;
AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: Skipping switch off relay %d"),i);
ExecuteCommandPower(i+1, 0, SRC_SHUTTER);
}
break;
Initial support for shutter button control New command "ShutterButton<x> <a> <b> <c> <d> <e> <f> <g> <h> <i> <j>" added that allows to assign a tasmota button <x> to control shutter <a>. Single press button shutter is set to position <b>. Double press button shutter is set to position <c>. Tripple press button shutter is set to position <d>. Hold button shutter is set to position <e>. Disabling any button action is given by <b> ... <e> equal to "-". Any press of the button while the shutter is moving will immediately stop that shutter. Global steering of all your shutters at home is supported by MQTT. By any button action an MQTT command can be initiated to the <grouptopic> of the device. For single press button this can be enabled by <f> equal to "1". Disabling is indicated by <f> equal to "0". Double to hold actions are given by <g> ... <i>, correspondingly. When <j> is equal to "0" only "cmnd/<grouptopic>/Shutterposition<y> ..." with <y>=<x> is fired. When <j> is equal to "1" <y>=1...4 is used to control any shutter number of a tasmota device having same <grouptopic>. Easy setup for an "up" button: ShutterButton<x> <a> up (same as ShutterButton<x> <a> 100 50 74 100 0 0 0 1 1) Single press will move shutter up to 100%, double press to 50% and tripple press to 74%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> up to 100%. Easy setup for an "down" button: ShutterButton<x> <a> down (same as ShutterButton<x> <a> 0 50 24 0 0 0 0 1 1) Single press will move shutter down to 0%, double press to 50% and tripple press to 24%. Holding the button for more than the hold time (SetOption32) moves all shutters with same <grouptopic> down to 0%. Easy setup for an "updown" button: ShutterButton<x> <a> updown (same as ShutterButton<x> <a> 100 0 50 - 0 0 0 0 0) Single press will move shutter up to 100%, double press down to 0% and tripple press to 50%. No hold action and no other shutter control by MQTT.
2020-01-02 10:23:11 +00:00
case FUNC_BUTTON_PRESSED:
if (Settings.shutter_button[XdrvMailbox.index] & (1<<31)) {
ShutterButtonHandler();
result = true;
}
break;
}
}
return result;
}
#endif //USE_SHUTTER