|
|
- /*
-
- KingArt Cover/Shutter/Blind/Curtain support for ESPURNA
-
- Based on xdrv_19_ps16dz.dimmer.ino, PS_16_DZ dimmer support for Tasmota
- Copyright (C) 2019 by Albert Weterings
-
- */
-
- #include "curtain_kingart.h"
-
- #if KINGART_CURTAIN_SUPPORT
-
- #include "ntp.h"
- #include "mqtt.h"
-
- #ifndef KINGART_CURTAIN_PORT
- #define KINGART_CURTAIN_PORT Serial // Hardware serial port by default
- #endif
-
- #ifndef KINGART_CURTAIN_BUFFER_SIZE
- #define KINGART_CURTAIN_BUFFER_SIZE 100 // Local UART buffer size
- #endif
-
- #define KINGART_CURTAIN_TERMINATION '\e' // Termination character after each message
- #define KINGART_CURTAIN_BAUDRATE 19200 // Serial speed is fixed for the device
-
- char _KACurtainBuffer[KINGART_CURTAIN_BUFFER_SIZE];
- bool _KACurtainNewData = false;
-
- // -----------------------------------------------------------------------------
- // Private
- // -----------------------------------------------------------------------------
-
- void _KACurtainSend(const char * tx_buffer) {
- KINGART_CURTAIN_PORT.print(tx_buffer);
- KINGART_CURTAIN_PORT.print(KINGART_CURTAIN_TERMINATION);
- KINGART_CURTAIN_PORT.flush();
- }
-
- void _KACurtainReceiveUART() {
- static unsigned char ndx = 0;
- while (KINGART_CURTAIN_PORT.available() > 0 && !_KACurtainNewData) {
- char rc = KINGART_CURTAIN_PORT.read();
- if (rc != KINGART_CURTAIN_TERMINATION) {
- _KACurtainBuffer[ndx] = rc;
- if (ndx < KINGART_CURTAIN_BUFFER_SIZE - 1) ndx++;
- } else {
- _KACurtainBuffer[ndx] = '\0';
- _KACurtainNewData = true;
- ndx = 0;
- }
- }
- }
-
- /*
- Buttons on the device will move Cover/Shutter/Blind/Curtain up/open or down/close On the end of
- every movement the unit reports the last action and posiston over MQTT topic {hostname}/curtain
-
- RAW paylod format looks like:
- AT+UPDATE="switch":"on","setclose":13
- AT+UPDATE="switch":"off","setclose":38
- AT+UPDATE="switch":"pause","setclose":75
-
- The device is listening to MQTT topic {hostname}/curtain/set, to which you can send:
- - position value, in range from 0 to 100
- - "pause", to stop the movement.
- The device will determine the direction all by itself.
-
- # Set the Cover / Shutter / Blind / Curtain run time
-
- The factory default Open and Close run time for the switch is 50 seconds, and it must be set to
- an accurate run time for smooth working. Some motors do not have the resistance stop function,
- so when the Cover/Shutter/Blind/Curtain track open or close to the maximum length, but the motor keeps on running.
- This might cause damage on the motor and the switch, it also wastes a lot of energy. In order
- to protect the motor, this switch designed with a time setting function. After setting up the run time,
- the switch will automaticly stop when the track reaches its limits. The run time setting is also helpful
- for the accurate control when manually controlling the device via the touch panel.
-
- After installing the switch and connecting the switch for the very first time:
- - First, it will automatically close the Cover/Shutter/Blind/Curtain to the maximum.
- - Press and hold the touch interface pause button for around 4 seconds until the red background
- led lights up and starts blinking. Then, press the open touch button so start the opening process.
- - When cover is fully open, press the Open or Close button to stop the timer and save the calculated run time.
-
- To configure the device:
- - Press up/down for 5 seconds to bring device into AP mode. After pressing up/down again, device will restart in normal mode.
- */
-
- void _KACurtainResult() {
- if (_KACurtainNewData) {
-
- // Need to send confiramtion to the N76E003AT20 that message is received
- _KACurtainSend("AT+SEND=ok");
-
- // We don't handle "setclose" any other way, simply redirect payload value
- const String buffer(_KACurtainBuffer);
- #if MQTT_SUPPORT
- int setclose_idx = buffer.indexOf("setclose");
- if (setclose_idx > 0) {
- auto position = buffer.substring(setclose_idx + strlen("setclose") + 2, buffer.length());
- int leftovers = position.indexOf(',');
- if (leftovers > 0) {
- position = position.substring(0, leftovers);
- }
- mqttSend(MQTT_TOPIC_CURTAIN, position.c_str());
- }
- #endif // MQTT_SUPPORT
-
- // Handle configuration button presses
- if (buffer.indexOf("enterESPTOUCH") > 0) {
- wifiStartAP();
- } else if (buffer.indexOf("exitESPTOUCH") > 0) {
- deferredReset(100, CUSTOM_RESET_HARDWARE);
- }
-
- _KACurtainNewData = false;
- }
- }
-
- // %d = now() / time_t / NTP timestamp in seconds
- // %03u = millis() / uint32_t / we need last 3 digits
- // %s = char strings for various actions
-
- // Tell N76E003AT20 to stop moving and report current position
- void _KACurtainPause(const char * message) {
- char tx_buffer[80] = {0};
- snprintf_P(
- tx_buffer, sizeof(tx_buffer),
- PSTR("AT+UPDATE=\"sequence\":\"%d%03u\",\"switch\":\"%s\""),
- now(), millis() % 1000,
- message
- );
- _KACurtainSend(tx_buffer);
- }
-
- // Tell N76E003AT20 to go to position X (based on X N76E003AT20 decides to go up or down)
- void _KACurtainSetclose(const char * message) {
- char tx_buffer[80] = {0};
- snprintf_P(
- tx_buffer, sizeof(tx_buffer),
- PSTR("AT+UPDATE=\"sequence\":\"%d%03u\",\"switch\":\"%s\",\"setclose\":%s"),
- now(), millis() % 1000,
- "off", message
- );
- _KACurtainSend(tx_buffer);
- }
-
- #if MQTT_SUPPORT
-
- void _KACurtainActionSelect(const char * message) {
- if (strcmp(message, "pause") == 0) {
- _KACurtainPause(message);
- } else {
- _KACurtainSetclose(message);
- }
- }
-
- void _KACurtainCallback(unsigned int type, const char * topic, char * payload) {
- if (type == MQTT_CONNECT_EVENT) {
- mqttSubscribe(MQTT_TOPIC_CURTAIN);
- }
- if (type == MQTT_MESSAGE_EVENT) {
- // Match topic
- const String t = mqttMagnitude(const_cast<char*>(topic));
- if (t.equals(MQTT_TOPIC_CURTAIN)) {
- _KACurtainActionSelect(payload);
- }
- }
- }
-
- #endif // MQTT_SUPPORT
-
- // -----------------------------------------------------------------------------
- // SETUP & LOOP
- // -----------------------------------------------------------------------------
-
- void _KACurtainLoop() {
- _KACurtainReceiveUART();
- _KACurtainResult();
- }
-
- void kingartCurtainSetup() {
-
- // Init port to receive and send messages
- KINGART_CURTAIN_PORT.begin(KINGART_CURTAIN_BAUDRATE);
-
- // Register MQTT callback only when supported
- #if MQTT_SUPPORT
- mqttRegister(_KACurtainCallback);
- #endif // MQTT_SUPPORT
-
- // Register loop to poll the UART for new messages
- espurnaRegisterLoop(_KACurtainLoop);
-
- }
-
- #endif // KINGART_CURTAIN_SUPPORT
|