Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for PS-16-DZ Dimmer #4465

Merged
merged 23 commits into from
Nov 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
64d6ef8
PS_16_DZ: initial support
chaosmaster Nov 24, 2018
dfc154a
PS_16_DZ: remove unwanted file
chaosmaster Nov 24, 2018
55b287d
PS_16_DZ: fix define in xdrv04
chaosmaster Nov 24, 2018
34da285
PS_16_DZ: fixes
chaosmaster Nov 24, 2018
9574fc7
PS_16_DZ: fixes
chaosmaster Nov 24, 2018
5ce19fc
PS_16_DZ: don't use String class
chaosmaster Nov 25, 2018
e024ca3
PS_16_DZ: start sequence with 1529000000000
chaosmaster Nov 25, 2018
0f2ea28
PS_16_DZ: start must be 'A'
chaosmaster Nov 25, 2018
977822f
PS_16_DZ: start must be 'A'
chaosmaster Nov 25, 2018
b7a18f7
PS_16_DZ: tryfix dimming
chaosmaster Nov 25, 2018
985db96
PS_16_DZ: print correct sequence
chaosmaster Nov 25, 2018
283f023
PS_16_DZ: move in nicelist
chaosmaster Nov 26, 2018
1dc7a58
PS_16_DZ: correctly parse sequence
chaosmaster Nov 26, 2018
7203d6a
PS_16_DZ: wait for acknoledgement before sending more commands
chaosmaster Nov 26, 2018
a6124c3
Revert "PS_16_DZ: wait for acknoledgement before sending more commands"
chaosmaster Nov 26, 2018
41ddab2
PS_16_DZ: flush serial after sending command
chaosmaster Nov 26, 2018
3650ab5
PS_16_DZ: use unix-timestamp as sequence
chaosmaster Nov 26, 2018
87d7609
PS_16_DZ: init sequence as 0
chaosmaster Nov 26, 2018
375a684
PS_16_DZ: merge development
chaosmaster Nov 26, 2018
6f6e438
PS_16_DZ: change logprefix to PSZ
chaosmaster Nov 26, 2018
7931b34
PS_16_DZ: bright as int
chaosmaster Nov 27, 2018
7e34f40
PS_16_DZ: GPIO13 => LED1
chaosmaster Nov 27, 2018
2811668
PS_16_DZ: cleanup code
chaosmaster Nov 27, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions sonoff/my_user_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@
#define USE_TUYA_DIMMER // Add support for Tuya Serial Dimmer
#define TUYA_DIMMER_ID 0 // Default dimmer Id
#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code)
#define USE_PS_16_DZ // ADD support for PS-16-DZ Dimmer

// Power monitoring sensors -----------------------
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
Expand Down
1 change: 1 addition & 0 deletions sonoff/sonoff_post.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ void KNX_CB_Action(message_t const &msg, void *arg);
#ifndef TUYA_DIMMER_ID
#define TUYA_DIMMER_ID 0 // Default dimmer Id
#endif
#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer
#define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code)
#define USE_PZEM_AC // Add support for PZEM014,016 Energy monitor (+1k1 code)
#define USE_PZEM_DC // Add support for PZEM003,017 Energy monitor (+1k1 code)
Expand Down
20 changes: 19 additions & 1 deletion sonoff/sonoff_template.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ enum SupportedModules {
GOSUND,
ARMTRONIX_DIMMERS,
SK03_TUYA,
PS_16_DZ,
MAXMODULE };

/********************************************************************************************/
Expand Down Expand Up @@ -481,8 +482,9 @@ const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = {
NEO_COOLCAM, // Socket Relay Devices
OBI,
ESP_SWITCH, // Switch Devices
TUYA_DIMMER, // Dimmer Devices
TUYA_DIMMER, // Dimmer Devices
ARMTRONIX_DIMMERS,
PS_16_DZ,
H801, // Light Devices
MAGICHOME,
ARILUX_LC01,
Expand Down Expand Up @@ -1273,6 +1275,22 @@ const mytmplt kModules[MAXMODULE] PROGMEM = {
GPIO_LED1_INV, // GPIO14 Blue Led (0 = On, 1 = Off)
GPIO_REL1, // GPIO15 Relay (0 = Off, 1 = On)
0, 0
},
{ "PS-16-DZ", // PS-16-DZ Dimmer (ESP8266 w/ separate Nuvoton MCU dimmer)
// https://www.aliexpress.com/item/SM-Smart-WIFI-Wall-Dimmer-Light-Switch-US-Ewelink-APP-Remote-Control-Wi-Fi-Wirele-Work/32871151902.html
GPIO_USER,
GPIO_TXD, // GPIO01 MCU serial control
GPIO_USER,
GPIO_RXD, // GPIO03 MCU serial control
GPIO_USER,
GPIO_USER,
0, 0, 0, 0, 0, 0, // Flash connection
GPIO_USER,
GPIO_LED1, // GPIO13 WiFi LED
GPIO_USER,
GPIO_USER,
GPIO_USER,
0
}
};

Expand Down
7 changes: 6 additions & 1 deletion sonoff/xdrv_04_light.ino
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,7 @@ void LightAnimate(void)
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
}
#ifdef USE_TUYA_DIMMER
if (light_type == LT_SERIAL1) {
if (light_type == LT_SERIAL1 && Settings.module == TUYA_DIMMER ) {
LightSerialDuty(cur_col[0]);
}
#endif // USE_TUYA_DIMMER
Expand All @@ -841,6 +841,11 @@ void LightAnimate(void)
LightSerial2Duty(cur_col[0],cur_col[1]);
}
#endif // USE_ARMTRONIX_DIMMERS
#ifdef USE_PS_16_DZ
if (light_type == LT_SERIAL1 && Settings.module == PS_16_DZ) {
PS16DZSerialDuty(cur_col[0]);
}
#endif // USE_PS_16_DZ

}
}
Expand Down
229 changes: 229 additions & 0 deletions sonoff/xdrv_19_ps16dz_dimmer.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/*
xdrv_19_ps16dz_dimmer.ino - PS_16_DZ dimmer support for Sonoff-Tasmota

Copyright (C) 2018 Joel Stein and Theo Arends

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_PS_16_DZ

#define XDRV_19 19

#define PS16DZ_BUFFER_SIZE 256

#include <TasmotaSerial.h>

TasmotaSerial *PS16DZSerial = nullptr;

boolean ps16dz_ignore_dim = false; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction

boolean ps16dz_power = false;
uint8_t ps16dz_bright = 0;
//uint64_t ps16dz_seq = 0;

char ps16dz_tx_buffer[PS16DZ_BUFFER_SIZE]; // Serial transmit buffer
char ps16dz_rx_buffer[PS16DZ_BUFFER_SIZE]; // Serial receive buffer
int ps16dz_byte_counter = 0;

/*********************************************************************************************\
* Internal Functions
\*********************************************************************************************/

void printTimestamp(void)
{
snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "%s%d%03d"), ps16dz_tx_buffer, LocalTime(), millis()%1000);
}

boolean PS16DZSetPower(void)
{
boolean status = false;

uint8_t rpower = XdrvMailbox.index;
int16_t source = XdrvMailbox.payload;

if (source != SRC_SWITCH && PS16DZSerial) { // ignore to prevent loop from pushing state from faceplate interaction

snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "AT+UPDATE=\"sequence\":\""));
printTimestamp();
snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "%s\",\"switch\":\"%s\""), ps16dz_tx_buffer, rpower?"on":"off");
snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send serial command: %s"), ps16dz_tx_buffer );
AddLog(LOG_LEVEL_DEBUG);

PS16DZSerial->print(ps16dz_tx_buffer);
PS16DZSerial->write(0x1B);
PS16DZSerial->flush();

status = true;
}
return status;
}

void PS16DZSerialDuty(uint8_t duty)
{
if (duty > 0 && !ps16dz_ignore_dim && PS16DZSerial) {
if (duty < 25) {
duty = 25; // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
}

snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "AT+UPDATE=\"sequence\":\""));
printTimestamp();
snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "%s\",\"bright\":%d"), ps16dz_tx_buffer, round(duty * (100. / 255.)));
snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send serial command: %s"), ps16dz_tx_buffer );
AddLog(LOG_LEVEL_DEBUG);

PS16DZSerial->print(ps16dz_tx_buffer);
PS16DZSerial->write(0x1B);
PS16DZSerial->flush();

} else {
ps16dz_ignore_dim = false; // reset flag

snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send Dim Level skipped due to 0 or already set. Value=%d"), duty);
AddLog(LOG_LEVEL_DEBUG);

}
}

void PS16DZResetWifi(void)
{
if (!Settings.flag.button_restrict) {
char scmnd[20];
snprintf_P(scmnd, sizeof(scmnd), D_CMND_WIFICONFIG " %d", 2);
ExecuteCommand(scmnd, SRC_BUTTON);
}
}

/*********************************************************************************************\
* API Functions
\*********************************************************************************************/

boolean PS16DZModuleSelected(void)
{
light_type = LT_SERIAL1;
return true;
}

void PS16DZInit(void)
{
PS16DZSerial = new TasmotaSerial(pin[GPIO_RXD], pin[GPIO_TXD], 2);
if (PS16DZSerial->begin(19200)) {
if (PS16DZSerial->hardwareSerial()) { ClaimSerial(); }
}
}

void PS16DZSerialInput(void)
{
char scmnd[20];
while (PS16DZSerial->available()) {
yield();
byte serial_in_byte = PS16DZSerial->read();
if (serial_in_byte != 0x1B){
if (ps16dz_byte_counter || (!ps16dz_byte_counter && serial_in_byte == 'A'));
ps16dz_rx_buffer[ps16dz_byte_counter++] = serial_in_byte;
}
else {
ps16dz_rx_buffer[ps16dz_byte_counter++] = 0x00;
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: command received: %s"), ps16dz_rx_buffer);
AddLog(LOG_LEVEL_DEBUG);
if(!strncmp(ps16dz_rx_buffer+3, "UPDATE", 6) || !strncmp(ps16dz_rx_buffer+3, "RESULT", 6)) {
char *end_str;
char *string = ps16dz_rx_buffer+10;
char* token = strtok_r(string, ",", &end_str);
while (token != NULL) {
char* end_token;
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: token = %s"), token);
AddLog(LOG_LEVEL_DEBUG);
char* token2 = strtok_r(token, ":", &end_token);
char* token3 = strtok_r(NULL, ":", &end_token);
if(!strncmp(token2, "\"switch\"", 8)){
ps16dz_power = !strncmp(token3, "\"on\"", 4)?true:false;
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: power received: %s"), token3);
AddLog(LOG_LEVEL_DEBUG);
if((power || Settings.light_dimmer > 0) && (power !=ps16dz_power)) {
ExecuteCommandPower(1, ps16dz_power, SRC_SWITCH); // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
}
}
else if(!strncmp(token2, "\"bright\"", 8)){
ps16dz_bright = atoi(token3);
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: brightness received: %d"), ps16dz_bright);
AddLog(LOG_LEVEL_DEBUG);
if(power && ps16dz_bright > 0) {

snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_DIMMER " %d"), ps16dz_bright );

snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: Send CMND_DIMMER_STR=%s"), scmnd );
AddLog(LOG_LEVEL_DEBUG);

ps16dz_ignore_dim = true;
ExecuteCommand(scmnd, SRC_SWITCH);
}
}
else if(!strncmp(token2, "\"sequence\"", 10)){
//ps16dz_seq = strtoull(token3+1, NULL, 10);
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: sequence received: %s"), token3);
AddLog(LOG_LEVEL_DEBUG);
}
token = strtok_r(NULL, ",", &end_str);
}
}
else if(!strncmp(ps16dz_rx_buffer+3, "SETTING", 7)) {
snprintf_P(log_data, sizeof(log_data), PSTR("PSZ: Reset"));
AddLog(LOG_LEVEL_DEBUG);
PS16DZResetWifi();
}
memset(ps16dz_rx_buffer, 0, sizeof(ps16dz_rx_buffer));
ps16dz_byte_counter = 0;

snprintf_P(ps16dz_tx_buffer, sizeof(ps16dz_tx_buffer), PSTR( "AT+SEND=ok"));
snprintf_P(log_data, sizeof(log_data), PSTR( "PSZ: Send serial command: %s"), ps16dz_tx_buffer );
AddLog(LOG_LEVEL_DEBUG);

PS16DZSerial->print(ps16dz_tx_buffer);
PS16DZSerial->write(0x1B);
PS16DZSerial->flush();
}
}
}



/*********************************************************************************************\
* Interface
\*********************************************************************************************/

boolean Xdrv19(byte function)
{
boolean result = false;

if (PS_16_DZ == Settings.module) {
switch (function) {
case FUNC_MODULE_INIT:
result = PS16DZModuleSelected();
break;
case FUNC_INIT:
PS16DZInit();
break;
case FUNC_LOOP:
if (PS16DZSerial) { PS16DZSerialInput(); }
break;
case FUNC_SET_DEVICE_POWER:
result = PS16DZSetPower();
break;
}
}
return result;
}

#endif // USE_PS_16_DZ