2018-10-18 12:01:31 +01:00
/*
xdrv_16_tuyadimmer . ino - Tuya dimmer support for Sonoff - Tasmota
2019-01-01 12:55:01 +00:00
Copyright ( C ) 2019 digiblur , Joel Stein and Theo Arends
2018-10-18 12:01:31 +01:00
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/>.
*/
2019-06-16 15:43:23 +01:00
# ifdef USE_LIGHT
2018-10-18 12:01:31 +01:00
# ifdef USE_TUYA_DIMMER
2018-11-07 09:30:03 +00:00
# define XDRV_16 16
2019-08-27 10:50:34 +01:00
# define XNRG_08 8
2018-11-07 09:30:03 +00:00
2018-10-18 12:01:31 +01:00
# ifndef TUYA_DIMMER_ID
2018-11-03 21:34:29 +00:00
# define TUYA_DIMMER_ID 0
2018-10-18 12:01:31 +01:00
# endif
2018-11-03 21:34:29 +00:00
# define TUYA_CMD_HEARTBEAT 0x00
# define TUYA_CMD_QUERY_PRODUCT 0x01
# define TUYA_CMD_MCU_CONF 0x02
# define TUYA_CMD_WIFI_STATE 0x03
# define TUYA_CMD_WIFI_RESET 0x04
# define TUYA_CMD_WIFI_SELECT 0x05
# define TUYA_CMD_SET_DP 0x06
# define TUYA_CMD_STATE 0x07
# define TUYA_CMD_QUERY_STATE 0x08
# define TUYA_TYPE_BOOL 0x01
# define TUYA_TYPE_VALUE 0x02
# define TUYA_BUFFER_SIZE 256
2018-10-18 12:01:31 +01:00
2018-10-27 02:01:09 +01:00
# include <TasmotaSerial.h>
2018-10-27 03:11:30 +01:00
TasmotaSerial * TuyaSerial = nullptr ;
2018-10-27 02:01:09 +01:00
2019-08-17 14:00:57 +01:00
struct TUYA {
uint8_t new_dim = 0 ; // Tuya dimmer value temp
bool ignore_dim = false ; // Flag to skip serial send to prevent looping when processing inbound states from the faceplate interaction
uint8_t cmd_status = 0 ; // Current status of serial-read
uint8_t cmd_checksum = 0 ; // Checksum of tuya command
uint8_t data_len = 0 ; // Data lenght of command
int8_t wifi_state = - 2 ; // Keep MCU wifi-status in sync with WifiState()
uint8_t heartbeat_timer = 0 ; // 10 second heartbeat timer for tuya module
2019-08-27 14:40:43 +01:00
# ifdef USE_ENERGY_SENSOR
2019-08-27 10:50:34 +01:00
uint32_t lastPowerCheckTime = 0 ; // Time when last power was checked
2019-08-27 14:40:43 +01:00
# endif // USE_ENERGY_SENSOR
2019-08-17 14:00:57 +01:00
char * buffer = nullptr ; // Serial receive buffer
int byte_counter = 0 ; // Index in serial receive buffer
} Tuya ;
2018-10-27 10:37:42 +01:00
2018-11-04 05:56:36 +00:00
/*********************************************************************************************\
* Internal Functions
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-07-02 14:49:08 +01:00
void TuyaSendCmd ( uint8_t cmd , uint8_t payload [ ] = nullptr , uint16_t payload_len = 0 )
{
2018-11-04 02:40:14 +00:00
uint8_t checksum = ( 0xFF + cmd + ( payload_len > > 8 ) + ( payload_len & 0xFF ) ) ;
2018-11-04 05:40:55 +00:00
TuyaSerial - > write ( 0x55 ) ; // Tuya header 55AA
TuyaSerial - > write ( 0xAA ) ;
2018-11-04 05:56:36 +00:00
TuyaSerial - > write ( ( uint8_t ) 0x00 ) ; // version 00
2018-11-04 05:40:55 +00:00
TuyaSerial - > write ( cmd ) ; // Tuya command
TuyaSerial - > write ( payload_len > > 8 ) ; // following data length (Hi)
TuyaSerial - > write ( payload_len & 0xFF ) ; // following data length (Lo)
2019-07-02 14:49:08 +01:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " TYA: Send \" 55aa00%02x%02x%02x " ) , cmd , payload_len > > 8 , payload_len & 0xFF ) ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < payload_len ; + + i ) {
2018-11-03 21:34:29 +00:00
TuyaSerial - > write ( payload [ i ] ) ;
checksum + = payload [ i ] ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s%02x " ) , log_data , payload [ i ] ) ;
}
TuyaSerial - > write ( checksum ) ;
TuyaSerial - > flush ( ) ;
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s%02x \" " ) , log_data , checksum ) ;
AddLog ( LOG_LEVEL_DEBUG ) ;
}
2019-07-02 14:49:08 +01:00
void TuyaSendState ( uint8_t id , uint8_t type , uint8_t * value )
{
2018-11-03 21:34:29 +00:00
uint16_t payload_len = 4 ;
uint8_t payload_buffer [ 8 ] ;
payload_buffer [ 0 ] = id ;
payload_buffer [ 1 ] = type ;
2019-07-02 14:49:08 +01:00
switch ( type ) {
2018-11-03 21:34:29 +00:00
case TUYA_TYPE_BOOL :
payload_len + = 1 ;
payload_buffer [ 2 ] = 0x00 ;
payload_buffer [ 3 ] = 0x01 ;
payload_buffer [ 4 ] = value [ 0 ] ;
break ;
case TUYA_TYPE_VALUE :
payload_len + = 4 ;
payload_buffer [ 2 ] = 0x00 ;
payload_buffer [ 3 ] = 0x04 ;
payload_buffer [ 4 ] = value [ 3 ] ;
payload_buffer [ 5 ] = value [ 2 ] ;
payload_buffer [ 6 ] = value [ 1 ] ;
payload_buffer [ 7 ] = value [ 0 ] ;
break ;
}
TuyaSendCmd ( TUYA_CMD_SET_DP , payload_buffer , payload_len ) ;
}
2019-07-02 14:49:08 +01:00
void TuyaSendBool ( uint8_t id , bool value )
{
TuyaSendState ( id , TUYA_TYPE_BOOL , ( uint8_t * ) & value ) ;
2018-11-03 21:34:29 +00:00
}
2019-07-02 14:49:08 +01:00
void TuyaSendValue ( uint8_t id , uint32_t value )
{
TuyaSendState ( id , TUYA_TYPE_VALUE , ( uint8_t * ) ( & value ) ) ;
2018-11-03 21:34:29 +00:00
}
2019-01-28 13:08:33 +00:00
bool TuyaSetPower ( void )
2018-10-18 12:01:31 +01:00
{
2019-01-28 13:08:33 +00:00
bool status = false ;
2018-10-18 12:01:31 +01:00
uint8_t rpower = XdrvMailbox . index ;
int16_t source = XdrvMailbox . payload ;
2018-10-27 03:11:30 +01:00
if ( source ! = SRC_SWITCH & & TuyaSerial ) { // ignore to prevent loop from pushing state from faceplate interaction
2019-06-08 10:38:45 +01:00
TuyaSendBool ( active_device , bitRead ( rpower , active_device - 1 ) ) ;
2018-10-18 12:01:31 +01:00
status = true ;
}
return status ;
}
2019-01-28 13:08:33 +00:00
bool TuyaSetChannels ( void )
2018-12-17 16:34:55 +00:00
{
LightSerialDuty ( ( ( uint8_t * ) XdrvMailbox . data ) [ 0 ] ) ;
2019-08-21 15:31:31 +01:00
delay ( 20 ) ; // Hack when power is off and dimmer is set then both commands go too soon to Serial out.
2018-12-17 16:34:55 +00:00
return true ;
}
2018-10-18 12:01:31 +01:00
void LightSerialDuty ( uint8_t duty )
{
2019-08-17 14:00:57 +01:00
if ( duty > 0 & & ! Tuya . ignore_dim & & TuyaSerial ) {
2019-08-14 14:52:37 +01:00
if ( Settings . flag3 . tuya_dimmer_min_limit ) { // Enable dimming limit SetOption69: Enabled by default
if ( duty < 25 ) { duty = 25 ; } // dimming acts odd below 25(10%) - this mirrors the threshold set on the faceplate itself
}
2018-11-07 09:30:03 +00:00
2019-08-22 13:46:42 +01:00
if ( Settings . flag3 . tuya_disable_dimmer = = 0 ) {
2019-08-25 22:10:19 +01:00
duty = changeUIntScale ( duty , 0 , 255 , 0 , Settings . param [ P_TUYA_DIMMER_MAX ] ) ;
2019-08-17 14:00:57 +01:00
if ( Tuya . new_dim ! = duty ) {
2019-08-14 13:53:46 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Send dim value=%d (id=%d) " ) , duty , Settings . param [ P_TUYA_DIMMER_ID ] ) ;
TuyaSendValue ( Settings . param [ P_TUYA_DIMMER_ID ] , duty ) ;
}
2019-07-02 14:49:08 +01:00
}
2018-10-18 12:01:31 +01:00
} else {
2019-08-17 14:00:57 +01:00
Tuya . ignore_dim = false ; // reset flag
2019-08-22 13:46:42 +01:00
if ( Settings . flag3 . tuya_disable_dimmer = = 0 ) {
2019-08-25 22:10:19 +01:00
duty = changeUIntScale ( duty , 0 , 255 , 0 , Settings . param [ P_TUYA_DIMMER_MAX ] ) ;
2019-07-02 14:49:08 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Send dim skipped value=%d " ) , duty ) ; // due to 0 or already set
2019-05-18 04:03:53 +01:00
}
2018-10-18 12:01:31 +01:00
}
}
2019-07-02 14:49:08 +01:00
void TuyaRequestState ( void )
{
if ( TuyaSerial ) {
2018-11-04 05:56:36 +00:00
// Get current status of MCU
2019-07-02 14:49:08 +01:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Read MCU state " ) ) ;
2018-11-04 05:56:36 +00:00
TuyaSendCmd ( TUYA_CMD_QUERY_STATE ) ;
}
}
2018-11-14 13:32:09 +00:00
void TuyaResetWifi ( void )
2018-11-04 05:56:36 +00:00
{
if ( ! Settings . flag . button_restrict ) {
char scmnd [ 20 ] ;
snprintf_P ( scmnd , sizeof ( scmnd ) , D_CMND_WIFICONFIG " %d " , 2 ) ;
ExecuteCommand ( scmnd , SRC_BUTTON ) ;
}
}
2018-11-14 13:32:09 +00:00
void TuyaPacketProcess ( void )
2018-10-18 12:01:31 +01:00
{
char scmnd [ 20 ] ;
2019-08-17 14:00:57 +01:00
switch ( Tuya . buffer [ 3 ] ) {
2018-10-18 12:01:31 +01:00
2018-11-07 09:30:03 +00:00
case TUYA_CMD_HEARTBEAT :
2018-11-03 21:34:29 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Heartbeat " ) ) ;
2019-08-17 14:00:57 +01:00
if ( Tuya . buffer [ 6 ] = = 0 ) {
2018-11-03 21:34:29 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Detected MCU restart " ) ) ;
2019-08-17 14:00:57 +01:00
Tuya . wifi_state = - 2 ;
2018-11-03 21:34:29 +00:00
}
break ;
2018-10-18 12:01:31 +01:00
2018-11-03 21:34:29 +00:00
case TUYA_CMD_STATE :
2019-08-17 14:00:57 +01:00
if ( Tuya . buffer [ 5 ] = = 5 ) { // on/off packet
2018-10-18 12:01:31 +01:00
2019-08-17 14:00:57 +01:00
/*if ((power || Settings.light_dimmer > 0) && (power != Tuya.buffer[10])) {
ExecuteCommandPower ( 1 , Tuya . buffer [ 10 ] , SRC_SWITCH ) ; // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
2019-05-18 04:03:53 +01:00
} */
2019-08-17 14:00:57 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX Device-%d --> MCU State: %s Current State:%s " ) , Tuya . buffer [ 6 ] , Tuya . buffer [ 10 ] ? " On " : " Off " , bitRead ( power , Tuya . buffer [ 6 ] - 1 ) ? " On " : " Off " ) ;
if ( ( power | | Settings . light_dimmer > 0 ) & & ( Tuya . buffer [ 10 ] ! = bitRead ( power , Tuya . buffer [ 6 ] - 1 ) ) ) {
ExecuteCommandPower ( Tuya . buffer [ 6 ] , Tuya . buffer [ 10 ] , SRC_SWITCH ) ; // send SRC_SWITCH? to use as flag to prevent loop from inbound states from faceplate interaction
2019-07-02 14:49:08 +01:00
}
2018-11-03 21:34:29 +00:00
}
2019-08-25 22:10:19 +01:00
else if ( Tuya . buffer [ 5 ] = = 8 ) { // Long value packet
2018-10-18 12:01:31 +01:00
2019-08-22 13:46:42 +01:00
if ( Settings . flag3 . tuya_disable_dimmer = = 0 ) {
2019-05-22 07:28:38 +01:00
if ( ! Settings . param [ P_TUYA_DIMMER_ID ] ) {
2019-08-17 14:00:57 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Autoconfiguring Dimmer ID %d " ) , Tuya . buffer [ 6 ] ) ;
Settings . param [ P_TUYA_DIMMER_ID ] = Tuya . buffer [ 6 ] ;
2019-05-22 07:28:38 +01:00
}
2019-08-17 14:00:57 +01:00
if ( Settings . param [ P_TUYA_DIMMER_ID ] = = Tuya . buffer [ 6 ] ) {
2019-08-25 22:10:19 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX Dim State=%d " ) , Tuya . buffer [ 13 ] ) ;
Tuya . new_dim = changeUIntScale ( ( uint8_t ) Tuya . buffer [ 13 ] , 0 , Settings . param [ P_TUYA_DIMMER_MAX ] , 0 , 100 ) ;
2019-08-17 14:00:57 +01:00
if ( ( power | | Settings . flag3 . tuya_apply_o20 ) & & ( Tuya . new_dim > 0 ) & & ( abs ( Tuya . new_dim - Settings . light_dimmer ) > 1 ) ) {
Tuya . ignore_dim = true ;
2019-08-14 13:53:46 +01:00
2019-08-17 14:00:57 +01:00
snprintf_P ( scmnd , sizeof ( scmnd ) , PSTR ( D_CMND_DIMMER " %d " ) , Tuya . new_dim ) ;
2019-08-14 13:53:46 +01:00
ExecuteCommand ( scmnd , SRC_SWITCH ) ;
}
2019-05-22 07:28:38 +01:00
}
2018-11-03 21:34:29 +00:00
}
2019-08-27 10:50:34 +01:00
2019-08-27 14:40:43 +01:00
# ifdef USE_ENERGY_SENSOR
2019-08-27 10:50:34 +01:00
if ( Settings . param [ P_TUYA_VOLTAGE_ID ] = = Tuya . buffer [ 6 ] ) {
Energy . voltage = ( float ) ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) / 10 ;
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Rx ID=%d Voltage=%d " ) , Settings . param [ P_TUYA_VOLTAGE_ID ] , ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) ) ;
} else if ( Settings . param [ P_TUYA_CURRENT_ID ] = = Tuya . buffer [ 6 ] ) {
Energy . current = ( float ) ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) / 1000 ;
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Rx ID=%d Current=%d " ) , Settings . param [ P_TUYA_CURRENT_ID ] , ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) ) ;
} else if ( Settings . param [ P_TUYA_POWER_ID ] = = Tuya . buffer [ 6 ] ) {
Energy . active_power = ( float ) ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) / 10 ;
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Rx ID=%d Active_Power=%d " ) , Settings . param [ P_TUYA_POWER_ID ] , ( Tuya . buffer [ 12 ] < < 8 | Tuya . buffer [ 13 ] ) ) ;
if ( Tuya . lastPowerCheckTime ! = 0 & & Energy . active_power > 0 ) {
Energy . kWhtoday + = ( float ) Energy . active_power * ( Rtc . utc_time - Tuya . lastPowerCheckTime ) / 36 ;
EnergyUpdateToday ( ) ;
}
Tuya . lastPowerCheckTime = Rtc . utc_time ;
} else if ( Settings . param [ P_TUYA_DIMMER_ID ] ! = Tuya . buffer [ 6 ] ) {
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX Unknown ID=%d " ) , Tuya . buffer [ 6 ] ) ;
}
2019-08-27 14:40:43 +01:00
# endif // USE_ENERGY_SENSOR
2018-11-01 01:55:16 +00:00
}
2018-11-03 21:34:29 +00:00
break ;
case TUYA_CMD_WIFI_RESET :
case TUYA_CMD_WIFI_SELECT :
2018-11-10 17:08:31 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX WiFi Reset " ) ) ;
2018-11-03 21:34:29 +00:00
TuyaResetWifi ( ) ;
break ;
case TUYA_CMD_WIFI_STATE :
2018-11-10 17:08:31 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX WiFi LED set ACK " ) ) ;
2019-08-17 14:00:57 +01:00
Tuya . wifi_state = WifiState ( ) ;
2018-11-03 21:34:29 +00:00
break ;
case TUYA_CMD_MCU_CONF :
2018-11-10 17:08:31 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX MCU configuration " ) ) ;
2018-11-03 21:34:29 +00:00
2019-08-17 14:00:57 +01:00
if ( Tuya . buffer [ 5 ] = = 2 ) {
uint8_t led1_gpio = Tuya . buffer [ 6 ] ;
uint8_t key1_gpio = Tuya . buffer [ 7 ] ;
2019-01-28 13:08:33 +00:00
bool key1_set = false ;
bool led1_set = false ;
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < sizeof ( Settings . my_gp ) ; i + + ) {
2018-11-03 21:34:29 +00:00
if ( Settings . my_gp . io [ i ] = = GPIO_LED1 ) led1_set = true ;
else if ( Settings . my_gp . io [ i ] = = GPIO_KEY1 ) key1_set = true ;
}
2019-07-02 14:49:08 +01:00
if ( ! Settings . my_gp . io [ led1_gpio ] & & ! led1_set ) {
2018-11-03 21:34:29 +00:00
Settings . my_gp . io [ led1_gpio ] = GPIO_LED1 ;
restart_flag = 2 ;
}
2019-07-02 14:49:08 +01:00
if ( ! Settings . my_gp . io [ key1_gpio ] & & ! key1_set ) {
2018-11-03 21:34:29 +00:00
Settings . my_gp . io [ key1_gpio ] = GPIO_KEY1 ;
restart_flag = 2 ;
}
2018-11-01 01:55:16 +00:00
}
2018-11-03 21:34:29 +00:00
TuyaRequestState ( ) ;
break ;
2018-11-04 02:40:14 +00:00
default :
2018-11-10 17:08:31 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: RX unknown command " ) ) ;
2018-11-01 01:55:16 +00:00
}
2018-10-18 12:01:31 +01:00
}
2018-11-04 05:56:36 +00:00
/*********************************************************************************************\
* API Functions
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool TuyaModuleSelected ( void )
2018-11-04 05:56:36 +00:00
{
if ( ! ( pin [ GPIO_TUYA_RX ] < 99 ) | | ! ( pin [ GPIO_TUYA_TX ] < 99 ) ) { // fallback to hardware-serial if not explicitly selected
pin [ GPIO_TUYA_TX ] = 1 ;
pin [ GPIO_TUYA_RX ] = 3 ;
Settings . my_gp . io [ 1 ] = GPIO_TUYA_TX ;
Settings . my_gp . io [ 3 ] = GPIO_TUYA_RX ;
restart_flag = 2 ;
}
2019-08-20 11:13:37 +01:00
if ( Settings . flag3 . tuya_disable_dimmer = = 0 ) {
light_type = LT_SERIAL1 ;
} else {
light_type = LT_BASIC ;
}
2018-11-04 05:56:36 +00:00
return true ;
}
2018-11-14 13:32:09 +00:00
void TuyaInit ( void )
2018-11-04 05:56:36 +00:00
{
2019-07-08 11:42:46 +01:00
devices_present + = Settings . param [ P_TUYA_RELAYS ] ; // SetOption41 - Add virtual relays if present
2018-11-04 05:56:36 +00:00
if ( ! Settings . param [ P_TUYA_DIMMER_ID ] ) {
Settings . param [ P_TUYA_DIMMER_ID ] = TUYA_DIMMER_ID ;
}
2019-08-17 14:00:57 +01:00
Tuya . buffer = ( char * ) ( malloc ( TUYA_BUFFER_SIZE ) ) ;
if ( Tuya . buffer ! = nullptr ) {
2018-11-27 10:55:54 +00:00
TuyaSerial = new TasmotaSerial ( pin [ GPIO_TUYA_RX ] , pin [ GPIO_TUYA_TX ] , 2 ) ;
if ( TuyaSerial - > begin ( 9600 ) ) {
if ( TuyaSerial - > hardwareSerial ( ) ) { ClaimSerial ( ) ; }
// Get MCU Configuration
2019-03-08 14:15:42 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Request MCU configuration " ) ) ;
2018-11-27 10:55:54 +00:00
TuyaSendCmd ( TUYA_CMD_MCU_CONF ) ;
}
2018-11-04 05:56:36 +00:00
}
2019-08-17 14:00:57 +01:00
Tuya . heartbeat_timer = 0 ; // init heartbeat timer when dimmer init is done
2018-11-04 05:56:36 +00:00
}
2018-11-14 13:32:09 +00:00
void TuyaSerialInput ( void )
2018-10-18 12:01:31 +01:00
{
2018-10-27 10:37:42 +01:00
while ( TuyaSerial - > available ( ) ) {
2018-10-18 12:01:31 +01:00
yield ( ) ;
2019-01-28 13:08:33 +00:00
uint8_t serial_in_byte = TuyaSerial - > read ( ) ;
2018-10-18 12:01:31 +01:00
if ( serial_in_byte = = 0x55 ) { // Start TUYA Packet
2019-08-17 14:00:57 +01:00
Tuya . cmd_status = 1 ;
Tuya . buffer [ Tuya . byte_counter + + ] = serial_in_byte ;
Tuya . cmd_checksum + = serial_in_byte ;
2018-10-18 12:01:31 +01:00
}
2019-08-17 14:00:57 +01:00
else if ( Tuya . cmd_status = = 1 & & serial_in_byte = = 0xAA ) { // Only packtes with header 0x55AA are valid
Tuya . cmd_status = 2 ;
2018-10-18 12:01:31 +01:00
2019-08-17 14:00:57 +01:00
Tuya . byte_counter = 0 ;
Tuya . buffer [ Tuya . byte_counter + + ] = 0x55 ;
Tuya . buffer [ Tuya . byte_counter + + ] = 0xAA ;
Tuya . cmd_checksum = 0xFF ;
2018-10-18 12:01:31 +01:00
}
2019-08-17 14:00:57 +01:00
else if ( Tuya . cmd_status = = 2 ) {
if ( Tuya . byte_counter = = 5 ) { // Get length of data
Tuya . cmd_status = 3 ;
Tuya . data_len = serial_in_byte ;
2018-10-18 12:01:31 +01:00
}
2019-08-17 14:00:57 +01:00
Tuya . cmd_checksum + = serial_in_byte ;
Tuya . buffer [ Tuya . byte_counter + + ] = serial_in_byte ;
2018-10-18 12:01:31 +01:00
}
2019-08-17 14:00:57 +01:00
else if ( ( Tuya . cmd_status = = 3 ) & & ( Tuya . byte_counter = = ( 6 + Tuya . data_len ) ) & & ( Tuya . cmd_checksum = = serial_in_byte ) ) { // Compare checksum and process packet
Tuya . buffer [ Tuya . byte_counter + + ] = serial_in_byte ;
2018-10-18 12:01:31 +01:00
2018-11-10 17:08:31 +00:00
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " TYA: RX Packet: \" " ) ) ;
2019-08-17 14:00:57 +01:00
for ( uint32_t i = 0 ; i < Tuya . byte_counter ; i + + ) {
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s%02x " ) , log_data , Tuya . buffer [ i ] ) ;
2018-10-18 12:01:31 +01:00
}
snprintf_P ( log_data , sizeof ( log_data ) , PSTR ( " %s \" " ) , log_data ) ;
AddLog ( LOG_LEVEL_DEBUG ) ;
TuyaPacketProcess ( ) ;
2019-08-17 14:00:57 +01:00
Tuya . byte_counter = 0 ;
Tuya . cmd_status = 0 ;
Tuya . cmd_checksum = 0 ;
Tuya . data_len = 0 ;
2018-10-18 12:01:31 +01:00
} // read additional packets from TUYA
2019-08-17 14:00:57 +01:00
else if ( Tuya . byte_counter < TUYA_BUFFER_SIZE - 1 ) { // add char to string if it still fits
Tuya . buffer [ Tuya . byte_counter + + ] = serial_in_byte ;
Tuya . cmd_checksum + = serial_in_byte ;
2018-10-18 12:01:31 +01:00
} else {
2019-08-17 14:00:57 +01:00
Tuya . byte_counter = 0 ;
Tuya . cmd_status = 0 ;
Tuya . cmd_checksum = 0 ;
Tuya . data_len = 0 ;
2018-10-18 12:01:31 +01:00
}
}
}
2019-01-28 13:08:33 +00:00
bool TuyaButtonPressed ( void )
2018-10-18 12:01:31 +01:00
{
2019-08-17 15:19:58 +01:00
if ( ! XdrvMailbox . index & & ( ( PRESSED = = XdrvMailbox . payload ) & & ( NOT_PRESSED = = Button . last_state [ XdrvMailbox . index ] ) ) ) {
2019-03-08 14:15:42 +00:00
AddLog_P ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Reset GPIO triggered " ) ) ;
2018-11-04 05:56:36 +00:00
TuyaResetWifi ( ) ;
return true ; // Reset GPIO served here
2018-10-27 10:37:42 +01:00
}
2018-11-04 05:56:36 +00:00
return false ; // Don't serve other buttons
2018-10-18 12:01:31 +01:00
}
2019-07-02 14:49:08 +01:00
void TuyaSetWifiLed ( void )
{
uint8_t wifi_state = 0x02 ;
switch ( WifiState ( ) ) {
case WIFI_SMARTCONFIG :
wifi_state = 0x00 ;
break ;
case WIFI_MANAGER :
case WIFI_WPSCONFIG :
wifi_state = 0x01 ;
break ;
case WIFI_RESTART :
wifi_state = 0x03 ;
break ;
}
2018-10-29 22:35:00 +00:00
2019-07-02 14:49:08 +01:00
AddLog_P2 ( LOG_LEVEL_DEBUG , PSTR ( " TYA: Set WiFi LED %d (%d) " ) , wifi_state , WifiState ( ) ) ;
2018-10-29 00:10:57 +00:00
2019-07-02 14:49:08 +01:00
TuyaSendCmd ( TUYA_CMD_WIFI_STATE , & wifi_state , 1 ) ;
2018-10-29 00:10:57 +00:00
}
2019-08-28 10:08:23 +01:00
# ifdef USE_ENERGY_SENSOR
/*********************************************************************************************\
* Energy Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int Xnrg08 ( uint8_t function )
{
int result = 0 ;
if ( TUYA_DIMMER = = my_module_type ) {
if ( FUNC_PRE_INIT = = function ) {
if ( ! energy_flg ) {
if ( Settings . param [ P_TUYA_POWER_ID ] ! = 0 ) {
if ( Settings . param [ P_TUYA_CURRENT_ID ] = = 0 ) {
Energy . current_available = false ;
}
if ( Settings . param [ P_TUYA_VOLTAGE_ID ] = = 0 ) {
Energy . voltage_available = false ;
}
energy_flg = XNRG_08 ;
}
}
}
}
return result ;
}
# endif // USE_ENERGY_SENSOR
2018-10-18 12:01:31 +01:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool Xdrv16 ( uint8_t function )
2018-10-18 12:01:31 +01:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-10-18 12:01:31 +01:00
2019-02-11 18:21:49 +00:00
if ( TUYA_DIMMER = = my_module_type ) {
2018-10-18 12:01:31 +01:00
switch ( function ) {
2019-03-30 12:03:45 +00:00
case FUNC_LOOP :
if ( TuyaSerial ) { TuyaSerialInput ( ) ; }
break ;
2018-10-18 12:01:31 +01:00
case FUNC_MODULE_INIT :
result = TuyaModuleSelected ( ) ;
break ;
case FUNC_INIT :
TuyaInit ( ) ;
break ;
2018-10-19 11:53:22 +01:00
case FUNC_SET_DEVICE_POWER :
2018-10-18 12:01:31 +01:00
result = TuyaSetPower ( ) ;
break ;
2018-10-19 11:53:22 +01:00
case FUNC_BUTTON_PRESSED :
result = TuyaButtonPressed ( ) ;
break ;
2018-10-29 00:10:57 +00:00
case FUNC_EVERY_SECOND :
2019-08-17 14:00:57 +01:00
if ( TuyaSerial & & Tuya . wifi_state ! = WifiState ( ) ) { TuyaSetWifiLed ( ) ; }
Tuya . heartbeat_timer + + ;
if ( Tuya . heartbeat_timer > 10 ) {
Tuya . heartbeat_timer = 0 ;
2019-07-02 14:49:08 +01:00
TuyaSendCmd ( TUYA_CMD_HEARTBEAT ) ;
2019-05-19 00:13:57 +01:00
}
2018-10-29 00:27:45 +00:00
break ;
2018-12-17 16:34:55 +00:00
case FUNC_SET_CHANNELS :
result = TuyaSetChannels ( ) ;
break ;
2018-10-18 12:01:31 +01:00
}
}
return result ;
}
2018-10-19 17:04:30 +01:00
# endif // USE_TUYA_DIMMER
2019-06-16 15:43:23 +01:00
# endif // USE_LIGHT