├── README.md ├── examples ├── AnalogJSON │ └── AnalogJSON.ino ├── Blink │ └── Blink.ino ├── BlinkSendCommand │ └── BlinkSendCommand.ino ├── SlaveRespondTele │ └── ClientRespondTele.ino └── SlaveSendCommand │ └── SlaveSendCommand.ino ├── keywords.txt ├── library.json ├── library.properties └── src ├── TasmotaClient.cpp └── TasmotaClient.h /README.md: -------------------------------------------------------------------------------- 1 | # TasmotaClient 2 | 3 | This library adds support for the TasmotaClient driver integrated into Tasmota from https://github.com/arendst/Tasmota 4 | 5 | Read the TasmotaClient wiki article on the Tasmota wiki from https://tasmota.github.io/docs/#/TasmotaSlave to see how to enable support for this library inside Tasmota. 6 | 7 | Edit:(docs are not up to date and dokuments the old TasmotaSlave comands) (2020-11-21) 8 | # Change Log 9 | 10 | ### 2019-11-29 - v0.0.2 (Pre-release) 11 | 12 | - Add support for sending commands to Tasmota using ExecuteCommand(char *cmnd) 13 | -------------------------------------------------------------------------------- /examples/AnalogJSON/AnalogJSON.ino: -------------------------------------------------------------------------------- 1 | /* 2 | AnalogJSON.ino - Example on how to send a JSON back to a Tasmota device 3 | which requested it on teleperiod. 4 | 5 | Copyright (C) 2019 Andre Thomas 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | TasmotaClient client(&Serial); 25 | 26 | /*******************************************************************\ 27 | * user_FUNC_JSON creates the JSON which will be sent back to the 28 | * Tasmota device upon receiving a request to do so 29 | \*******************************************************************/ 30 | 31 | void user_FUNC_JSON(void) 32 | { 33 | uint8_t a = 0; 34 | char myjson[100]; 35 | sprintf(myjson,"{\"A0\": %u, \"A1\": %u, \"A2\": %u, \"A3\": %u, \"A4\": %u, \"A5\": %u, \"A6\": %u, \"A7\": %u}", analogRead(A0), analogRead(A1), analogRead(A2), analogRead(A3), analogRead(A4), analogRead(A5), analogRead(A6), analogRead(A7)); 36 | client.sendJSON(myjson); 37 | } 38 | 39 | /*******************************************************************\ 40 | * Normal setup() function for Arduino to configure the serial port 41 | * speed (which should match what was configured in Tasmota, and 42 | * attach the function which will be called when the Tasmota device 43 | * reuqests a new JSON (usually on Teleperiod on Tasmota device) 44 | \*******************************************************************/ 45 | 46 | void setup() { 47 | // Configure the serial port speed 48 | Serial.begin(57600); 49 | // Attach the callback function which will provide the JSON to Tasmota 50 | client.attach_FUNC_JSON(user_FUNC_JSON); 51 | } 52 | 53 | void loop() { 54 | // Call the client loop function every so often to process incoming requests 55 | client.loop(); 56 | } 57 | -------------------------------------------------------------------------------- /examples/Blink/Blink.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Blink.ino - Example for TasmotaClient receiving the FUNC_EVERY_SECOND 3 | callback and respond by toggling the LED as configured. 4 | 5 | Copyright (C) 2019 Andre Thomas 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . 19 | */ 20 | 21 | #include 22 | #include 23 | 24 | TasmotaClient client(&Serial); 25 | 26 | bool ledstate = false; 27 | 28 | /*******************************************************************\ 29 | * Function which will be called when Tasmota sends a 30 | * FUNC_EVERY_SECOND command 31 | \*******************************************************************/ 32 | 33 | void user_FUNC_EVERY_SECOND(void) 34 | { 35 | if (ledstate) { 36 | ledstate = false; 37 | digitalWrite(LED_BUILTIN, LOW); 38 | } else { 39 | ledstate = true; 40 | digitalWrite(LED_BUILTIN, HIGH); 41 | } 42 | } 43 | 44 | /*******************************************************************\ 45 | * Normal setup() function for Arduino to configure the serial port 46 | * speed (which should match what was configured in Tasmota) and 47 | * attach any callback functions associated with specific requests 48 | * or commands that are sent by Tasmota. 49 | \*******************************************************************/ 50 | 51 | void setup() { 52 | // Configure serial port 53 | Serial.begin(57600); 54 | // We're going to use the builtin LED so lets configure the pin as OUTPUT 55 | pinMode(LED_BUILTIN, OUTPUT); 56 | // Attach the callback function which will be called when Tasmota requests it 57 | client.attach_FUNC_EVERY_SECOND(user_FUNC_EVERY_SECOND); 58 | } 59 | 60 | void loop() { 61 | // Call the client loop function every so often to process incoming requests 62 | client.loop(); 63 | } 64 | -------------------------------------------------------------------------------- /examples/BlinkSendCommand/BlinkSendCommand.ino: -------------------------------------------------------------------------------- 1 | /* 2 | BlinkRelay.ino - Example for TasmotaClient receiving the FUNC_EVERY_SECOND 3 | callback and respond by toggling the LED as configured. 4 | This example also extends sending commands back to the 5 | Tasmota device by which could be any command normally 6 | executed from the console but in this particular example 7 | we just use a simple publish command. 8 | 9 | Copyright (C) 2019 Andre Thomas 10 | 11 | This program is free software: you can redistribute it and/or modify 12 | it under the terms of the GNU General Public License as published by 13 | the Free Software Foundation, either version 3 of the License, or 14 | (at your option) any later version. 15 | 16 | This program is distributed in the hope that it will be useful, 17 | but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | GNU General Public License for more details. 20 | 21 | You should have received a copy of the GNU General Public License 22 | along with this program. If not, see . 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | TasmotaClient client(&Serial); 29 | 30 | bool ledstate = false; 31 | 32 | /*******************************************************************\ 33 | * Function which will be called when Tasmota sends a 34 | * FUNC_EVERY_SECOND command 35 | \*******************************************************************/ 36 | 37 | void user_FUNC_EVERY_SECOND(void) 38 | { 39 | if (ledstate) { 40 | ledstate = false; 41 | digitalWrite(LED_BUILTIN, LOW); 42 | } else { 43 | ledstate = true; 44 | digitalWrite(LED_BUILTIN, HIGH); 45 | } 46 | if (ledstate) { 47 | client.ExecuteCommand((char*)"publish tele/mytopic/power on"); 48 | } else { 49 | client.ExecuteCommand((char*)"publish tele/mytopic/power off"); 50 | } 51 | } 52 | 53 | /*******************************************************************\ 54 | * Normal setup() function for Arduino to configure the serial port 55 | * speed (which should match what was configured in Tasmota) and 56 | * attach any callback functions associated with specific requests 57 | * or commands that are sent by Tasmota. 58 | \*******************************************************************/ 59 | 60 | void setup() { 61 | // Configure serial port 62 | Serial.begin(57600); 63 | // We're going to use the builtin LED so lets configure the pin as OUTPUT 64 | pinMode(LED_BUILTIN, OUTPUT); 65 | // Attach the callback function which will be called when Tasmota requests it 66 | client.attach_FUNC_EVERY_SECOND(user_FUNC_EVERY_SECOND); 67 | } 68 | 69 | void loop() { 70 | // Call the client loop function every so often to process incoming requests 71 | client.loop(); 72 | } 73 | -------------------------------------------------------------------------------- /examples/SlaveRespondTele/ClientRespondTele.ino: -------------------------------------------------------------------------------- 1 | /* 2 | ClientRespondTele.ino - Example for TasmotaClient to respond to ClientSend ON and 3 | ClientSend OFF commands via console or telemetry. 4 | In this example the ON and OFF is case sensitive so needs 5 | to be sent in capital letters from the Tasmota device. 6 | Upon receiving ON/OFF the client will turn the LED on/off 7 | respectively and respond with a telemetry message sent 8 | back to Tasmota that will be published for telemetry 9 | and rules processing on the Tasmota device. 10 | 11 | Copyright (C) 2019 Andre Thomas 12 | 13 | This program is free software: you can redistribute it and/or modify 14 | it under the terms of the GNU General Public License as published by 15 | the Free Software Foundation, either version 3 of the License, or 16 | (at your option) any later version. 17 | 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | 23 | You should have received a copy of the GNU General Public License 24 | along with this program. If not, see . 25 | */ 26 | 27 | #include 28 | #include 29 | 30 | TasmotaClient client(&Serial); 31 | 32 | /*******************************************************************\ 33 | * Normal setup() function for Arduino to configure the serial port 34 | * speed (which should match what was configured in Tasmota) and 35 | * attach any callback functions associated with specific requests 36 | * or commands that are sent by Tasmota. 37 | \*******************************************************************/ 38 | 39 | void setup() { 40 | // Configure the LED pin as OUTPUT 41 | pinMode(LED_BUILTIN, OUTPUT); 42 | // Configure the serial port for the correct baud rate 43 | Serial.begin(57600); 44 | // Attach the callback function which will be called when Tasmota requests it 45 | client.attach_FUNC_COMMAND_SEND(user_FUNC_RECEIVE); 46 | } 47 | 48 | /*******************************************************************\ 49 | * Function which will be called when Tasmota sends a 50 | * ClientSend command 51 | \*******************************************************************/ 52 | 53 | void user_FUNC_RECEIVE(char *data) 54 | { 55 | if (!strcmp(data, "ON")) { // ClientSend ON 56 | digitalWrite(LED_BUILTIN, HIGH); 57 | char response[20]; 58 | sprintf(response,"{\"LED\":\"ON\"}"); 59 | client.SendTele(response); 60 | } 61 | if (!strcmp(data, "OFF")) { // ClientSend OFF 62 | digitalWrite(LED_BUILTIN, LOW); 63 | char response[20]; 64 | sprintf(response,"{\"LED\":\"OFF\"}"); 65 | client.SendTele(response); 66 | } 67 | } 68 | 69 | void loop() { 70 | client.loop(); // Call the client loop function every so often to process incoming requests 71 | } 72 | -------------------------------------------------------------------------------- /examples/SlaveSendCommand/SlaveSendCommand.ino: -------------------------------------------------------------------------------- 1 | /* 2 | SlaveSendCommand.ino - Example for TasmotaSlave to respond to SlaveSend ON and 3 | SlaveSend OFF commands via console or telemetry. 4 | In this example the ON and OFF is case sensitive so needs 5 | to be sent in capital letters from the Tasmota device. 6 | Upon receiving ON/OFF the slave will turn the LED on/off 7 | respectively. 8 | 9 | A second function callback is also attached which will 10 | respond with a JSON message on Tasmota Teleperiod when 11 | requested from the Tasmota device. 12 | 13 | Copyright (C) 2019 Andre Thomas 14 | This program is free software: you can redistribute it and/or modify 15 | it under the terms of the GNU General Public License as published by 16 | the Free Software Foundation, either version 3 of the License, or 17 | (at your option) any later version. 18 | This program is distributed in the hope that it will be useful, 19 | but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | GNU General Public License for more details. 22 | You should have received a copy of the GNU General Public License 23 | along with this program. If not, see . 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | TasmotaSlave slave(&Serial); 30 | 31 | /*******************************************************************\ 32 | * Normal setup() function for Arduino to configure the serial port 33 | * speed (which should match what was configured in Tasmota) and 34 | * attach any callback functions associated with specific requests 35 | * or commands that are sent by Tasmota. 36 | \*******************************************************************/ 37 | 38 | void setup() { 39 | // Configure the LED pin as OUTPUT 40 | pinMode(LED_BUILTIN, OUTPUT); 41 | // Configure the serial port baud rate 42 | Serial.begin(57600); 43 | // Attach the function which will respond to the JSON request from Tasmota 44 | slave.attach_FUNC_JSON(user_FUNC_JSON); 45 | // Attach the function which will be called when the Tasmota device sends data using SlaveSend command 46 | slave.attach_FUNC_COMMAND_SEND(user_FUNC_RECEIVE); 47 | } 48 | 49 | /*******************************************************************\ 50 | * Function which will be called when this slave device receives a 51 | * SlaveSend command from the Tasmota device. 52 | \*******************************************************************/ 53 | 54 | void user_FUNC_RECEIVE(char *data) 55 | { 56 | if (!strcmp(data, "ON")) { // SlaveSend ON 57 | digitalWrite(LED_BUILTIN, HIGH); 58 | } 59 | if (!strcmp(data, "OFF")) { // SlaveSend OFF 60 | digitalWrite(LED_BUILTIN, LOW); 61 | } 62 | } 63 | 64 | /*******************************************************************\ 65 | * user_FUNC_JSON creates the JSON which will be sent back to the 66 | * Tasmota device upon receiving a request to do so 67 | \*******************************************************************/ 68 | 69 | void user_FUNC_JSON(void) 70 | { 71 | uint8_t a = 0; 72 | char myjson[100]; 73 | sprintf(myjson,"{\"A0\": %u, \"A1\": %u, \"A2\": %u, \"A3\": %u, \"A4\": %u, \"A5\": %u, \"A6\": %u, \"A7\": %u}", analogRead(A0), analogRead(A1), analogRead(A2), analogRead(A3), analogRead(A4), analogRead(A5), analogRead(A6), analogRead(A7)); 74 | slave.sendJSON(myjson); 75 | } 76 | 77 | void loop() { 78 | // Call the slave loop every so often to process any incoming requests 79 | slave.loop(); 80 | } 81 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map for TasmotaClient 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | TasmotaClient KEYWORD1 10 | 11 | ####################################### 12 | # Methods and Functions (KEYWORD2) 13 | ####################################### 14 | 15 | receive_buffer KEYWORD2 16 | sendFeatures KEYWORD2 17 | sendJSON KEYWORD2 18 | attach_FUNC_JSON KEYWORD2 19 | attach_FUNC_EVERY_SECOND KEYWORD2 20 | attach_FUNC_EVERY_100_MSECOND KEYWORD2 21 | attach_FUNC_COMMAND_SEND KEYWORD2 22 | SendCommand KEYWORD2 23 | SendTele KEYWORD2 24 | waitforbytes KEYWORD2 25 | ProcessSend KEYWORD2 26 | ProcessCommand KEYWORD2 27 | ExecuteCommand KEYWORD2 28 | loop KEYWORD2 29 | 30 | ####################################### 31 | # Constants (LITERAL1) 32 | ####################################### 33 | 34 | -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TasmotaClient", 3 | "version": "0.0.2", 4 | "keywords": [ 5 | "serial", "io", "TasmotaClient" 6 | ], 7 | "description": "TasmotaClient Driver Library", 8 | "repository": 9 | { 10 | "type": "git", 11 | "url": "https://github.com/andrethomas/TasmotaSlave" 12 | }, 13 | "frameworks": "arduino" 14 | } 15 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=TasmotaSlave 2 | version=0.0.2 3 | author=Andre Thomas 4 | maintainer=Andre Thomas 5 | sentence=TasmotaSlave Driver Library for Arduino 6 | paragraph= 7 | category=Signal Input/Output 8 | url= 9 | architectures=avr,esp8266,esp32,samd,sam,stm32,STM32F1,megaavr,teensy,samd_beta,atmelavr,arm,stm32f4,atmelsam,STM32F4,megaAVR,esp 10 | -------------------------------------------------------------------------------- /src/TasmotaClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | TasmotaClient.cpp - Library for microcontrollers enclientd by Tasmota 3 | 4 | Copyright (C) 2019 Andre Thomas 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | /*************************************************\ 24 | * TasmotaClient shared structures 25 | \*************************************************/ 26 | 27 | typedef union { 28 | uint32_t data; 29 | struct { 30 | uint32_t func_json_append : 1; // Supports FUNC_JSON_APPEND callback 31 | uint32_t func_every_second : 1; // Supports FUNC_EVERY_SECOND callback (No JSON) 32 | uint32_t func_every_100_msecond : 1; // Supports FUNC_EVERY_100_MSECOND callback (No JSON) 33 | uint32_t func_client_send : 1; // Supports FUNC_COMMAND 34 | uint32_t spare4 : 1; 35 | uint32_t spare5 : 1; 36 | uint32_t spare6 : 1; 37 | uint32_t spare7 : 1; 38 | uint32_t spare8 : 1; 39 | uint32_t spare9 : 1; 40 | uint32_t spare10 : 1; 41 | uint32_t spare11 : 1; 42 | uint32_t spare12 : 1; 43 | uint32_t spare13 : 1; 44 | uint32_t spare14 : 1; 45 | uint32_t spare15 : 1; 46 | uint32_t spare16 : 1; 47 | uint32_t spare17 : 1; 48 | uint32_t spare18 : 1; 49 | uint32_t spare19 : 1; 50 | uint32_t spare20 : 1; 51 | uint32_t spare21 : 1; 52 | uint32_t spare22 : 1; 53 | uint32_t spare23 : 1; 54 | uint32_t spare24 : 1; 55 | uint32_t spare25 : 1; 56 | uint32_t spare26 : 1; 57 | uint32_t spare27 : 1; 58 | uint32_t spare28 : 1; 59 | uint32_t spare29 : 1; 60 | uint32_t spare30 : 1; 61 | uint32_t spare31 : 1; 62 | }; 63 | } FeatureCfg; 64 | 65 | /**************************************************\ 66 | * Settings structure - MUST remain 4 byte aligned 67 | \**************************************************/ 68 | 69 | struct FEATURES { 70 | uint32_t features_version; 71 | FeatureCfg features; 72 | } Settings; 73 | 74 | /********************************************************************************\ 75 | * Command structure for sending/receiving commands - MUST remain 4 byte aligned 76 | \********************************************************************************/ 77 | 78 | struct COMMAND { 79 | uint8_t command; 80 | uint8_t parameter; 81 | uint8_t unused2; 82 | uint8_t unused3; 83 | } Command; 84 | 85 | TasmotaClient::TasmotaClient(HardwareSerial *device) 86 | { 87 | serial = device; 88 | Settings.features_version = TASMOTA_CLIENT_LIB_VERSION; 89 | Settings.features.func_json_append = 0; 90 | Settings.features.func_every_second = 0; 91 | Settings.features.func_every_100_msecond = 0; 92 | Settings.features.func_client_send = 0; 93 | Settings.features.spare4 = 0; 94 | Settings.features.spare5 = 0; 95 | Settings.features.spare6 = 0; 96 | Settings.features.spare7 = 0; 97 | Settings.features.spare8 = 0; 98 | Settings.features.spare9 = 0; 99 | Settings.features.spare10 = 0; 100 | Settings.features.spare11 = 0; 101 | Settings.features.spare12 = 0; 102 | Settings.features.spare13 = 0; 103 | Settings.features.spare14 = 0; 104 | Settings.features.spare15 = 0; 105 | Settings.features.spare16 = 0; 106 | Settings.features.spare17 = 0; 107 | Settings.features.spare18 = 0; 108 | Settings.features.spare19 = 0; 109 | Settings.features.spare20 = 0; 110 | Settings.features.spare21 = 0; 111 | Settings.features.spare22 = 0; 112 | Settings.features.spare23 = 0; 113 | Settings.features.spare24 = 0; 114 | Settings.features.spare25 = 0; 115 | Settings.features.spare26 = 0; 116 | Settings.features.spare27 = 0; 117 | Settings.features.spare28 = 0; 118 | Settings.features.spare29 = 0; 119 | Settings.features.spare30 = 0; 120 | Settings.features.spare31 = 0; 121 | } 122 | 123 | void TasmotaClient::sendFeatures(void) 124 | { 125 | char buffer[sizeof(Settings)]; 126 | memcpy(&buffer, &Settings, sizeof(Settings)); 127 | serial->write(char(PARAM_DATA_START)); 128 | for (uint8_t ca = 0; ca < sizeof(buffer); ca++) { 129 | serial->write(char(buffer[ca])); 130 | } 131 | serial->write(char(PARAM_DATA_END)); 132 | } 133 | 134 | void TasmotaClient::sendJSON(char *json) 135 | { 136 | serial->write(char(PARAM_DATA_START)); 137 | for (uint8_t ca = 0; ca < strlen(json); ca++) { 138 | serial->write(json[ca]); 139 | } 140 | serial->write(char(PARAM_DATA_END)); 141 | } 142 | 143 | void TasmotaClient::attach_FUNC_JSON(callbackFunc func) 144 | { 145 | Settings.features.func_json_append = 1; 146 | FUNC_JSON = func; 147 | } 148 | 149 | void TasmotaClient::attach_FUNC_EVERY_SECOND(callbackFunc func) 150 | { 151 | Settings.features.func_every_second = 1; 152 | FUNC_EVERY_SECOND = func; 153 | } 154 | 155 | void TasmotaClient::attach_FUNC_EVERY_100_MSECOND(callbackFunc func) 156 | { 157 | Settings.features.func_every_100_msecond = 1; 158 | FUNC_EVERY_100_MSECOND = func; 159 | } 160 | 161 | void TasmotaClient::attach_FUNC_COMMAND_SEND(callbackFunc1 func) 162 | { 163 | Settings.features.func_client_send = 1; 164 | FUNC_SEND = func; 165 | } 166 | 167 | uint8_t TasmotaClient::waitforbytes(uint16_t num, uint16_t timeout) 168 | { 169 | uint16_t timer = 0; 170 | while (timer < timeout) { 171 | if (serial->available() > (int)(num-1)) { 172 | return 1; 173 | } 174 | delay(1); 175 | timer++; 176 | } 177 | return 0; 178 | } 179 | 180 | void TasmotaClient::ProcessSend(uint8_t sz) 181 | { 182 | if (waitforbytes(sz+2,50)) { 183 | serial->read(); // read leading character 184 | for (uint8_t idx = 0; idx < sz; idx++) { 185 | receive_buffer[idx] = serial->read(); 186 | } 187 | serial->read(); // read trailing byte 188 | receive_buffer[sz] = '\0'; 189 | FUNC_SEND(receive_buffer); 190 | } 191 | } 192 | 193 | void TasmotaClient::ProcessCommand(void) 194 | { 195 | if (waitforbytes(sizeof(Command)+1, 100)) { 196 | char buffer[sizeof(Command)]; 197 | for (uint8_t idx = 0; idx < sizeof(Command); idx++) { 198 | buffer[idx] = serial->read(); 199 | } 200 | serial->read(); // Remove end of command character 201 | memcpy(&Command, &buffer, sizeof(Command)); 202 | switch (Command.command) { 203 | case CMND_FEATURES: 204 | sendFeatures(); 205 | break; 206 | case CMND_FUNC_JSON: 207 | FUNC_JSON(); 208 | break; 209 | case CMND_FUNC_EVERY_SECOND: 210 | FUNC_EVERY_SECOND(); 211 | break; 212 | case CMND_FUNC_EVERY_100_MSECOND: 213 | FUNC_EVERY_100_MSECOND(); 214 | break; 215 | case CMND_CLIENT_SEND: 216 | ProcessSend(Command.parameter); 217 | break; 218 | default: 219 | break; 220 | } 221 | } 222 | } 223 | 224 | void TasmotaClient::SendCommand(uint8_t cmnd, uint8_t param) 225 | { 226 | Command.command = cmnd; 227 | Command.parameter = param; 228 | Command.unused2 = 0; 229 | Command.unused3 = 0; 230 | uint8_t tmp[sizeof(Command)]; 231 | memcpy(&tmp, &Command, sizeof(Command)); 232 | serial->write(char(CMND_START)); 233 | for (uint8_t idx = 0; idx < sizeof(Command); idx++) { 234 | serial->write(tmp[idx]); 235 | } 236 | serial->write(char(CMND_END)); 237 | } 238 | 239 | void TasmotaClient::SendTele(char *data) 240 | { 241 | SendCommand(CMND_PUBLISH_TELE, strlen(data)); 242 | serial->write(char(PARAM_DATA_START)); 243 | for (uint8_t idx = 0; idx < strlen(data); idx++) { 244 | serial->write(data[idx]); 245 | } 246 | serial->write(char(PARAM_DATA_END)); 247 | } 248 | 249 | void TasmotaClient::ExecuteCommand(char *cmnd) 250 | { 251 | SendCommand(CMND_EXECUTE_CMND, strlen(cmnd)); 252 | serial->write(char(PARAM_DATA_START)); 253 | for (uint8_t idx = 0; idx < strlen(cmnd); idx++) { 254 | serial->write(cmnd[idx]); 255 | } 256 | serial->write(char(PARAM_DATA_END)); 257 | } 258 | 259 | void TasmotaClient::loop(void) 260 | { 261 | if (serial->available()) { 262 | uint8_t cmnd = serial->read(); 263 | switch (cmnd) { 264 | case CMND_START: 265 | ProcessCommand(); 266 | break; 267 | default: 268 | break; 269 | } 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/TasmotaClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | TasmotaClient.h - Library for microcontrollers enslaved by Tasmota 3 | 4 | Copyright (C) 2019 Andre Thomas 5 | 6 | This program is free software: you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License as published by 8 | the Free Software Foundation, either version 3 of the License, or 9 | (at your option) any later version. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License 17 | along with this program. If not, see . 18 | */ 19 | 20 | #ifndef __TASMOTACLIENT_H__ 21 | #define __TASMOTACLIENT_H__ 22 | 23 | #include 24 | 25 | /*************************************************\ 26 | * TasmotaClient Configuration Defaults 27 | \*************************************************/ 28 | 29 | #define TASMOTA_CLIENT_LIB_VERSION 20191129 30 | 31 | /*************************************************\ 32 | * TasmotaClient Command definitions 33 | \*************************************************/ 34 | 35 | #define CMND_START 0xFC 36 | #define CMND_END 0xFD 37 | 38 | #define CMND_FEATURES 0x01 39 | #define CMND_FUNC_JSON 0x02 40 | #define CMND_FUNC_EVERY_SECOND 0x03 41 | #define CMND_FUNC_EVERY_100_MSECOND 0x04 42 | #define CMND_CLIENT_SEND 0x05 43 | #define CMND_PUBLISH_TELE 0x06 44 | #define CMND_EXECUTE_CMND 0x07 45 | 46 | /*************************************************\ 47 | * TasmotaClient Parameter defintions 48 | \*************************************************/ 49 | 50 | #define PARAM_DATA_START 0xFE 51 | #define PARAM_DATA_END 0xFF 52 | 53 | /*************************************************\ 54 | * Prototypes for passing functions as parameters 55 | \*************************************************/ 56 | 57 | typedef void (*callbackFunc) (void); 58 | typedef void (*callbackFunc1) (char*); 59 | 60 | /*************************************************\ 61 | * TasmotaClient Class 62 | \*************************************************/ 63 | 64 | class TasmotaClient { 65 | public: 66 | char receive_buffer[100]; 67 | // Constructor 68 | TasmotaClient(HardwareSerial *device = nullptr); 69 | // Sends configured features back to Tasmota so it knows which callbacks are supported 70 | void sendFeatures(void); 71 | // Send JSON back to Tasmota device 72 | void sendJSON(char *json); 73 | // Configure a callback for FUNC_JSON 74 | void attach_FUNC_JSON(callbackFunc func = nullptr); 75 | // Configure a callback for FUNC_EVERY_SECOND 76 | void attach_FUNC_EVERY_SECOND(callbackFunc func = nullptr); 77 | // Configure a callback for FUNC_EVERY_100_MSECOND 78 | void attach_FUNC_EVERY_100_MSECOND(callbackFunc func = nullptr); 79 | // Configure a callback for FUNC_COMMAND_SEND (ClientSend on Tasmota device) 80 | void attach_FUNC_COMMAND_SEND(callbackFunc1 func = nullptr); 81 | // Send command to Tasmota device using the prescribed protocol 82 | void SendCommand(uint8_t cmnd, uint8_t param); 83 | // Send telemetry data back to the Tasmota device 84 | void SendTele(char *data); 85 | // Used internally (should probably be moved to private:) 86 | uint8_t waitforbytes(uint16_t num, uint16_t timeout); 87 | // Used internally to process incoming ClientSend command 88 | void ProcessSend(uint8_t sz); 89 | // Used internally to decode and process incoming commands from the Tasmota device 90 | void ProcessCommand(void); 91 | // Main client loop which needs to be serviced occasionally to process incoming requests 92 | void ExecuteCommand(char *cmnd); 93 | void loop(void); 94 | private: 95 | HardwareSerial *serial; 96 | callbackFunc FUNC_JSON; 97 | callbackFunc FUNC_EVERY_SECOND; 98 | callbackFunc FUNC_EVERY_100_MSECOND; 99 | callbackFunc1 FUNC_SEND; 100 | }; 101 | 102 | #endif // __TASMOTACLIENT_H__ 103 | --------------------------------------------------------------------------------