├── lib └── Base64 │ ├── AUTHORS │ ├── LICENSE │ ├── base64.cpp │ ├── base64.h │ ├── cdecode.c │ ├── cdecode.h │ ├── cencode.c │ └── cencode.h └── src ├── ArduinoEasy.ino ├── Command.ino ├── Controller.ino ├── Hardware.ino ├── Misc.ino ├── Networking.ino ├── Serial.ino ├── WebServer.ino ├── _C001.ino ├── _C002.ino ├── _C005.ino ├── _P001_Switch.ino ├── _P002_ADC.ino ├── _P003_Pulse.ino ├── _P004_Dallas.ino ├── _P005_DHT.ino ├── _P033_Dummy.ino ├── _P034_DHT12.ino ├── __CPlugin.ino ├── __Plugin.ino └── __ReleaseNotes.ino /lib/Base64/AUTHORS: -------------------------------------------------------------------------------- 1 | libb64: Base64 Encoding/Decoding Routines 2 | ====================================== 3 | 4 | Authors: 5 | ------- 6 | 7 | Chris Venter chris.venter@gmail.com http://rocketpod.blogspot.com 8 | -------------------------------------------------------------------------------- /lib/Base64/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright-Only Dedication (based on United States law) 2 | or Public Domain Certification 3 | 4 | The person or persons who have associated work with this document (the 5 | "Dedicator" or "Certifier") hereby either (a) certifies that, to the best of 6 | his knowledge, the work of authorship identified is in the public domain of the 7 | country from which the work is published, or (b) hereby dedicates whatever 8 | copyright the dedicators holds in the work of authorship identified below (the 9 | "Work") to the public domain. A certifier, moreover, dedicates any copyright 10 | interest he may have in the associated work, and for these purposes, is 11 | described as a "dedicator" below. 12 | 13 | A certifier has taken reasonable steps to verify the copyright status of this 14 | work. Certifier recognizes that his good faith efforts may not shield him from 15 | liability if in fact the work certified is not in the public domain. 16 | 17 | Dedicator makes this dedication for the benefit of the public at large and to 18 | the detriment of the Dedicator's heirs and successors. Dedicator intends this 19 | dedication to be an overt act of relinquishment in perpetuity of all present 20 | and future rights under copyright law, whether vested or contingent, in the 21 | Work. Dedicator understands that such relinquishment of all rights includes 22 | the relinquishment of all rights to enforce (by lawsuit or otherwise) those 23 | copyrights in the Work. 24 | 25 | Dedicator recognizes that, once placed in the public domain, the Work may be 26 | freely reproduced, distributed, transmitted, used, modified, built upon, or 27 | otherwise exploited by anyone for any purpose, commercial or non-commercial, 28 | and in any way, including by methods that have not yet been invented or 29 | conceived. -------------------------------------------------------------------------------- /lib/Base64/base64.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * base64.cpp 3 | * 4 | * Created on: 09.12.2015 5 | * 6 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 7 | * This file is part of the ESP8266 core for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include "Arduino.h" 26 | extern "C" { 27 | #include "cdecode.h" 28 | #include "cencode.h" 29 | } 30 | #include "base64.h" 31 | 32 | /** 33 | * convert input data to base64 34 | * @param data uint8_t * 35 | * @param length size_t 36 | * @return String 37 | */ 38 | String base64::encode(uint8_t * data, size_t length) { 39 | // base64 needs more size then the source data 40 | size_t size = ((length * 1.6f) + 1); 41 | char * buffer = (char *) malloc(size); 42 | if(buffer) { 43 | base64_encodestate _state; 44 | base64_init_encodestate(&_state); 45 | int len = base64_encode_block((const char *) &data[0], length, &buffer[0], &_state); 46 | len = base64_encode_blockend((buffer + len), &_state); 47 | 48 | String base64 = String(buffer); 49 | free(buffer); 50 | return base64; 51 | } 52 | return String("-FAIL-"); 53 | } 54 | 55 | /** 56 | * convert input data to base64 57 | * @param text String 58 | * @return String 59 | */ 60 | String base64::encode(String text) { 61 | return base64::encode((uint8_t *) text.c_str(), text.length()); 62 | } 63 | 64 | -------------------------------------------------------------------------------- /lib/Base64/base64.h: -------------------------------------------------------------------------------- 1 | /** 2 | * base64.h 3 | * 4 | * Created on: 09.12.2015 5 | * 6 | * Copyright (c) 2015 Markus Sattler. All rights reserved. 7 | * This file is part of the ESP8266 core for Arduino. 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #ifndef CORE_BASE64_H_ 26 | #define CORE_BASE64_H_ 27 | 28 | class base64 { 29 | public: 30 | static String encode(uint8_t * data, size_t length); 31 | static String encode(String text); 32 | private: 33 | }; 34 | 35 | 36 | #endif /* CORE_BASE64_H_ */ 37 | -------------------------------------------------------------------------------- /lib/Base64/cdecode.c: -------------------------------------------------------------------------------- 1 | /* 2 | cdecoder.c - c source to a base64 decoding algorithm implementation 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #include "cdecode.h" 9 | 10 | int base64_decode_value(char value_in){ 11 | static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; 12 | static const char decoding_size = sizeof(decoding); 13 | value_in -= 43; 14 | if (value_in < 0 || value_in > decoding_size) return -1; 15 | return decoding[(int)value_in]; 16 | } 17 | 18 | void base64_init_decodestate(base64_decodestate* state_in){ 19 | state_in->step = step_a; 20 | state_in->plainchar = 0; 21 | } 22 | 23 | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in){ 24 | const char* codechar = code_in; 25 | char* plainchar = plaintext_out; 26 | char fragment; 27 | 28 | *plainchar = state_in->plainchar; 29 | 30 | switch (state_in->step){ 31 | while (1){ 32 | case step_a: 33 | do { 34 | if (codechar == code_in+length_in){ 35 | state_in->step = step_a; 36 | state_in->plainchar = *plainchar; 37 | return plainchar - plaintext_out; 38 | } 39 | fragment = (char)base64_decode_value(*codechar++); 40 | } while (fragment < 0); 41 | *plainchar = (fragment & 0x03f) << 2; 42 | case step_b: 43 | do { 44 | if (codechar == code_in+length_in){ 45 | state_in->step = step_b; 46 | state_in->plainchar = *plainchar; 47 | return plainchar - plaintext_out; 48 | } 49 | fragment = (char)base64_decode_value(*codechar++); 50 | } while (fragment < 0); 51 | *plainchar++ |= (fragment & 0x030) >> 4; 52 | *plainchar = (fragment & 0x00f) << 4; 53 | case step_c: 54 | do { 55 | if (codechar == code_in+length_in){ 56 | state_in->step = step_c; 57 | state_in->plainchar = *plainchar; 58 | return plainchar - plaintext_out; 59 | } 60 | fragment = (char)base64_decode_value(*codechar++); 61 | } while (fragment < 0); 62 | *plainchar++ |= (fragment & 0x03c) >> 2; 63 | *plainchar = (fragment & 0x003) << 6; 64 | case step_d: 65 | do { 66 | if (codechar == code_in+length_in){ 67 | state_in->step = step_d; 68 | state_in->plainchar = *plainchar; 69 | return plainchar - plaintext_out; 70 | } 71 | fragment = (char)base64_decode_value(*codechar++); 72 | } while (fragment < 0); 73 | *plainchar++ |= (fragment & 0x03f); 74 | } 75 | } 76 | /* control should not reach here */ 77 | return plainchar - plaintext_out; 78 | } 79 | 80 | int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out){ 81 | base64_decodestate _state; 82 | base64_init_decodestate(&_state); 83 | int len = base64_decode_block(code_in, length_in, plaintext_out, &_state); 84 | if(len > 0) plaintext_out[len] = 0; 85 | return len; 86 | } 87 | -------------------------------------------------------------------------------- /lib/Base64/cdecode.h: -------------------------------------------------------------------------------- 1 | /* 2 | cdecode.h - c header for a base64 decoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CDECODE_H 9 | #define BASE64_CDECODE_H 10 | 11 | #define base64_decode_expected_len(n) ((n * 3) / 4) 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef enum { 18 | step_a, step_b, step_c, step_d 19 | } base64_decodestep; 20 | 21 | typedef struct { 22 | base64_decodestep step; 23 | char plainchar; 24 | } base64_decodestate; 25 | 26 | void base64_init_decodestate(base64_decodestate* state_in); 27 | 28 | int base64_decode_value(char value_in); 29 | 30 | int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); 31 | 32 | int base64_decode_chars(const char* code_in, const int length_in, char* plaintext_out); 33 | 34 | #ifdef __cplusplus 35 | } // extern "C" 36 | #endif 37 | 38 | #endif /* BASE64_CDECODE_H */ 39 | -------------------------------------------------------------------------------- /lib/Base64/cencode.c: -------------------------------------------------------------------------------- 1 | /* 2 | cencoder.c - c source to a base64 encoding algorithm implementation 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #include "cencode.h" 9 | 10 | const int CHARS_PER_LINE = 72; 11 | 12 | void base64_init_encodestate(base64_encodestate* state_in){ 13 | state_in->step = step_A; 14 | state_in->result = 0; 15 | state_in->stepcount = 0; 16 | } 17 | 18 | char base64_encode_value(char value_in){ 19 | static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 20 | if (value_in > 63) return '='; 21 | return encoding[(int)value_in]; 22 | } 23 | 24 | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in){ 25 | const char* plainchar = plaintext_in; 26 | const char* const plaintextend = plaintext_in + length_in; 27 | char* codechar = code_out; 28 | char result; 29 | char fragment; 30 | 31 | result = state_in->result; 32 | 33 | switch (state_in->step){ 34 | while (1){ 35 | case step_A: 36 | if (plainchar == plaintextend){ 37 | state_in->result = result; 38 | state_in->step = step_A; 39 | return codechar - code_out; 40 | } 41 | fragment = *plainchar++; 42 | result = (fragment & 0x0fc) >> 2; 43 | *codechar++ = base64_encode_value(result); 44 | result = (fragment & 0x003) << 4; 45 | case step_B: 46 | if (plainchar == plaintextend){ 47 | state_in->result = result; 48 | state_in->step = step_B; 49 | return codechar - code_out; 50 | } 51 | fragment = *plainchar++; 52 | result |= (fragment & 0x0f0) >> 4; 53 | *codechar++ = base64_encode_value(result); 54 | result = (fragment & 0x00f) << 2; 55 | case step_C: 56 | if (plainchar == plaintextend){ 57 | state_in->result = result; 58 | state_in->step = step_C; 59 | return codechar - code_out; 60 | } 61 | fragment = *plainchar++; 62 | result |= (fragment & 0x0c0) >> 6; 63 | *codechar++ = base64_encode_value(result); 64 | result = (fragment & 0x03f) >> 0; 65 | *codechar++ = base64_encode_value(result); 66 | 67 | ++(state_in->stepcount); 68 | if (state_in->stepcount == CHARS_PER_LINE/4){ 69 | *codechar++ = '\n'; 70 | state_in->stepcount = 0; 71 | } 72 | } 73 | } 74 | /* control should not reach here */ 75 | return codechar - code_out; 76 | } 77 | 78 | int base64_encode_blockend(char* code_out, base64_encodestate* state_in){ 79 | char* codechar = code_out; 80 | 81 | switch (state_in->step){ 82 | case step_B: 83 | *codechar++ = base64_encode_value(state_in->result); 84 | *codechar++ = '='; 85 | *codechar++ = '='; 86 | break; 87 | case step_C: 88 | *codechar++ = base64_encode_value(state_in->result); 89 | *codechar++ = '='; 90 | break; 91 | case step_A: 92 | break; 93 | } 94 | *codechar = 0x00; 95 | 96 | return codechar - code_out; 97 | } 98 | 99 | int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out){ 100 | base64_encodestate _state; 101 | base64_init_encodestate(&_state); 102 | int len = base64_encode_block(plaintext_in, length_in, code_out, &_state); 103 | return len + base64_encode_blockend((code_out + len), &_state); 104 | } 105 | -------------------------------------------------------------------------------- /lib/Base64/cencode.h: -------------------------------------------------------------------------------- 1 | /* 2 | cencode.h - c header for a base64 encoding algorithm 3 | 4 | This is part of the libb64 project, and has been placed in the public domain. 5 | For details, see http://sourceforge.net/projects/libb64 6 | */ 7 | 8 | #ifndef BASE64_CENCODE_H 9 | #define BASE64_CENCODE_H 10 | 11 | #define base64_encode_expected_len(n) ((((4 * n) / 3) + 3) & ~3) 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef enum { 18 | step_A, step_B, step_C 19 | } base64_encodestep; 20 | 21 | typedef struct { 22 | base64_encodestep step; 23 | char result; 24 | int stepcount; 25 | } base64_encodestate; 26 | 27 | void base64_init_encodestate(base64_encodestate* state_in); 28 | 29 | char base64_encode_value(char value_in); 30 | 31 | int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); 32 | 33 | int base64_encode_blockend(char* code_out, base64_encodestate* state_in); 34 | 35 | int base64_encode_chars(const char* plaintext_in, int length_in, char* code_out); 36 | 37 | #ifdef __cplusplus 38 | } // extern "C" 39 | #endif 40 | 41 | #endif /* BASE64_CENCODE_H */ 42 | -------------------------------------------------------------------------------- /src/ArduinoEasy.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************************************************************\ 2 | * Arduino project "Arduino Easy" © Copyright www.letscontrolit.com 3 | * 4 | * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 6 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 7 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 8 | * You received a copy of the GNU General Public License along with this program in file 'License.txt'. 9 | * 10 | * IDE download : https://www.arduino.cc/en/Main/Software 11 | * 12 | * Source Code : https://github.com/ESP8266nu/ESPEasy 13 | * Support : http://www.letscontrolit.com 14 | * Discussion : http://www.letscontrolit.com/forum/ 15 | * 16 | * Additional information about licensing can be found at : http://www.gnu.org/licenses 17 | \*************************************************************************************************************************/ 18 | 19 | // This file incorporates work covered by the following copyright and permission notice: 20 | 21 | /****************************************************************************************************************************\ 22 | * Arduino project "Nodo" © Copyright 2010..2015 Paul Tonkes 23 | * 24 | * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 25 | * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 26 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 27 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 28 | * You received a copy of the GNU General Public License along with this program in file 'License.txt'. 29 | * 30 | * Voor toelichting op de licentievoorwaarden zie : http://www.gnu.org/licenses 31 | * Uitgebreide documentatie is te vinden op : http://www.nodo-domotica.nl 32 | * Compiler voor deze programmacode te downloaden op : http://arduino.cc 33 | \*************************************************************************************************************************/ 34 | 35 | // ******************************************************************************** 36 | // User specific configuration 37 | // ******************************************************************************** 38 | 39 | 40 | //#define DEBUG_WEB 41 | 42 | // Set default configuration settings if you want (not mandatory) 43 | // You can always change these during runtime and save to eeprom 44 | // After loading firmware, issue a 'reset' command to load the defaults. 45 | 46 | #define DEFAULT_NAME "newdevice" // Enter your device friendly name 47 | #define DEFAULT_SERVER "192.168.0.8" // Enter your Domoticz Server IP address 48 | #define DEFAULT_PORT 8080 // Enter your Domoticz Server port value 49 | #define DEFAULT_DELAY 60 // Enter your Send delay in seconds 50 | 51 | #define DEFAULT_USE_STATIC_IP false // true or false enabled or disabled set static IP 52 | #define DEFAULT_IP "192.168.0.50" // Enter your IP address 53 | #define DEFAULT_DNS "192.168.0.1" // Enter your DNS 54 | #define DEFAULT_GW "192.168.0.1" // Enter your gateway 55 | #define DEFAULT_SUBNET "255.255.255.0" // Enter your subnet 56 | 57 | #define DEFAULT_PROTOCOL 1 // Protocol used for controller communications 58 | #define UNIT 0 59 | 60 | #define FEATURE_MQTT true 61 | #define FEATURE_MQTT_DOM false // Not tested yet! 62 | #define FEATURE_NODELIST_NAMES true 63 | #define FEATURE_NODELIST_NAMESSIZE 10 64 | 65 | // ******************************************************************************** 66 | // DO NOT CHANGE ANYTHING BELOW THIS LINE 67 | // ******************************************************************************** 68 | 69 | // Challenges on Arduino/W5100 ethernet platform: 70 | // Only 4 ethernet sockets: 71 | // 1: UPD traffic server/send 72 | // 2: Webserver 73 | // 3: MQTT client 74 | // 4: Webclient, active when webserver serves an incoming client or outgoing webclient calls. 75 | 76 | #define socketdebug false 77 | #define ARDUINO_PROJECT_PID 2016110201L 78 | #define VERSION 2 79 | #define BUILD 154 80 | #define BUILD_NOTES "" 81 | 82 | #define NODE_TYPE_ID_ESP_EASY_STD 1 83 | #define NODE_TYPE_ID_ESP_EASYM_STD 17 84 | #define NODE_TYPE_ID_ESP_EASY32_STD 33 85 | #define NODE_TYPE_ID_ARDUINO_EASY_STD 65 86 | #define NODE_TYPE_ID_NANO_EASY_STD 81 87 | #define NODE_TYPE_ID NODE_TYPE_ID_ARDUINO_EASY_STD 88 | 89 | #define CPLUGIN_PROTOCOL_ADD 1 90 | #define CPLUGIN_PROTOCOL_TEMPLATE 2 91 | #define CPLUGIN_PROTOCOL_SEND 3 92 | #define CPLUGIN_PROTOCOL_RECV 4 93 | #define CPLUGIN_GET_DEVICENAME 5 94 | #define CPLUGIN_WEBFORM_SAVE 6 95 | #define CPLUGIN_WEBFORM_LOAD 7 96 | 97 | #define LOG_LEVEL_ERROR 1 98 | #define LOG_LEVEL_INFO 2 99 | #define LOG_LEVEL_DEBUG 3 100 | #define LOG_LEVEL_DEBUG_MORE 4 101 | 102 | #define CMD_REBOOT 89 103 | 104 | #define DEVICES_MAX 8 // ESP Easy 64 105 | #define TASKS_MAX 8 // ESP Easy 12 106 | #define VARS_PER_TASK 4 107 | #define PLUGIN_MAX 8 // ESP Easy 64 108 | #define PLUGIN_CONFIGVAR_MAX 8 109 | #define PLUGIN_CONFIGFLOATVAR_MAX 4 110 | #define PLUGIN_CONFIGLONGVAR_MAX 4 111 | #define PLUGIN_EXTRACONFIGVAR_MAX 16 112 | #define CPLUGIN_MAX 4 // ESP Easy 16 113 | #define UNIT_MAX 32 // Only relevant for UDP unicast message 'sweeps' and the nodelist. 114 | #define RULES_TIMER_MAX 8 115 | #define SYSTEM_TIMER_MAX 2 // ESP Easy 8 116 | #define SYSTEM_CMD_TIMER_MAX 1 // ESP Easy 2 117 | #define PINSTATE_TABLE_MAX 16 // ESP Easy 32 118 | #define RULES_MAX_SIZE 512 // ESP Easy 2048 119 | #define RULES_MAX_NESTING_LEVEL 3 120 | 121 | #define PIN_MODE_UNDEFINED 0 122 | #define PIN_MODE_INPUT 1 123 | #define PIN_MODE_OUTPUT 2 124 | #define PIN_MODE_PWM 3 125 | #define PIN_MODE_SERVO 4 126 | 127 | #define SEARCH_PIN_STATE true 128 | #define NO_SEARCH_PIN_STATE false 129 | 130 | #define DEVICE_TYPE_SINGLE 1 // connected through 1 datapin 131 | #define DEVICE_TYPE_I2C 2 // connected through I2C 132 | #define DEVICE_TYPE_ANALOG 3 // tout pin 133 | #define DEVICE_TYPE_DUAL 4 // connected through 2 datapins 134 | #define DEVICE_TYPE_DUMMY 99 // Dummy device, has no physical connection 135 | 136 | #define SENSOR_TYPE_SINGLE 1 137 | #define SENSOR_TYPE_TEMP_HUM 2 138 | #define SENSOR_TYPE_TEMP_BARO 3 139 | #define SENSOR_TYPE_TEMP_HUM_BARO 4 140 | #define SENSOR_TYPE_DUAL 5 141 | #define SENSOR_TYPE_TRIPLE 6 142 | #define SENSOR_TYPE_QUAD 7 143 | #define SENSOR_TYPE_SWITCH 10 144 | #define SENSOR_TYPE_DIMMER 11 145 | #define SENSOR_TYPE_LONG 20 146 | 147 | #define PLUGIN_INIT_ALL 1 148 | #define PLUGIN_INIT 2 149 | #define PLUGIN_READ 3 150 | #define PLUGIN_ONCE_A_SECOND 4 151 | #define PLUGIN_TEN_PER_SECOND 5 152 | #define PLUGIN_DEVICE_ADD 6 153 | #define PLUGIN_EVENTLIST_ADD 7 154 | #define PLUGIN_WEBFORM_SAVE 8 155 | #define PLUGIN_WEBFORM_LOAD 9 156 | #define PLUGIN_WEBFORM_SHOW_VALUES 10 157 | #define PLUGIN_GET_DEVICENAME 11 158 | #define PLUGIN_GET_DEVICEVALUENAMES 12 159 | #define PLUGIN_WRITE 13 160 | #define PLUGIN_EVENT_OUT 14 161 | #define PLUGIN_WEBFORM_SHOW_CONFIG 15 162 | #define PLUGIN_SERIAL_IN 16 163 | #define PLUGIN_UDP_IN 17 164 | #define PLUGIN_CLOCK_IN 18 165 | #define PLUGIN_TIMER_IN 19 166 | 167 | #define VALUE_SOURCE_SYSTEM 1 168 | #define VALUE_SOURCE_SERIAL 2 169 | #define VALUE_SOURCE_HTTP 3 170 | #define VALUE_SOURCE_MQTT 4 171 | #define VALUE_SOURCE_UDP 5 172 | 173 | #define INT_MIN -32767 174 | #define INT_MAX 32767 175 | 176 | #include 177 | #include 178 | #include 179 | #include 180 | #include 181 | #include 182 | #if FEATURE_MQTT 183 | #include 184 | #include 185 | #endif 186 | #include 187 | 188 | void(*Reboot)(void)=0; 189 | 190 | byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; 191 | 192 | // WebServer 193 | EthernetServer MyWebServer(80); 194 | 195 | #if FEATURE_MQTT 196 | EthernetClient mqtt; 197 | PubSubClient MQTTclient(mqtt); 198 | #endif 199 | 200 | #define EthernetShield_CS_SDCard 4 201 | #define EthernetShield_CS_W5100 10 202 | 203 | // syslog stuff 204 | EthernetUDP portUDP; 205 | 206 | struct SecurityStruct 207 | { 208 | char ControllerUser[26]; 209 | char ControllerPassword[64]; 210 | char Password[26]; 211 | } SecuritySettings; 212 | 213 | struct SettingsStruct 214 | { 215 | unsigned long PID; 216 | int Version; 217 | byte Unit; 218 | int16_t Build; 219 | byte IP[4]; 220 | byte Gateway[4]; 221 | byte Subnet[4]; 222 | byte DNS[4]; 223 | byte Controller_IP[4]; 224 | unsigned int ControllerPort; 225 | byte IP_Octet; 226 | char NTPHost[64]; 227 | unsigned long Delay; 228 | byte Syslog_IP[4]; 229 | unsigned int UDPPort; 230 | byte Protocol; 231 | char Name[26]; 232 | byte SyslogLevel; 233 | byte SerialLogLevel; 234 | unsigned long BaudRate; 235 | unsigned long MessageDelay; 236 | boolean CustomCSS; 237 | char ControllerHostName[64]; 238 | boolean UseNTP; 239 | boolean DST; 240 | byte WDI2CAddress; 241 | int8_t PinBootStates[17]; 242 | byte UseDNS; 243 | boolean UseRules; 244 | int8_t Pin_status_led; 245 | boolean UseSerial; 246 | boolean GlobalSync; 247 | unsigned long ConnectionFailuresThreshold; 248 | int16_t TimeZone; 249 | byte SDLogLevel; 250 | byte TaskDeviceNumber[TASKS_MAX]; 251 | unsigned int TaskDeviceID[TASKS_MAX]; 252 | int8_t TaskDevicePin1[TASKS_MAX]; 253 | int8_t TaskDevicePin2[TASKS_MAX]; 254 | byte TaskDevicePort[TASKS_MAX]; 255 | boolean TaskDevicePin1PullUp[TASKS_MAX]; 256 | int16_t TaskDevicePluginConfig[TASKS_MAX][PLUGIN_CONFIGVAR_MAX]; 257 | boolean TaskDevicePin1Inversed[TASKS_MAX]; 258 | float TaskDevicePluginConfigFloat[TASKS_MAX][PLUGIN_CONFIGFLOATVAR_MAX]; 259 | long TaskDevicePluginConfigLong[TASKS_MAX][PLUGIN_CONFIGLONGVAR_MAX]; 260 | boolean TaskDeviceSendData[TASKS_MAX]; 261 | boolean TaskDeviceGlobalSync[TASKS_MAX]; 262 | int8_t TaskDevicePin3[TASKS_MAX]; 263 | byte TaskDeviceDataFeed[TASKS_MAX]; 264 | unsigned long TaskDeviceTimer[TASKS_MAX]; 265 | boolean MQTTRetainFlag; 266 | char MQTTpublish[81]; 267 | char MQTTsubscribe[81]; 268 | } Settings; 269 | 270 | struct ExtraTaskSettingsStruct 271 | { 272 | byte TaskIndex; 273 | char TaskDeviceName[41]; 274 | char TaskDeviceFormula[VARS_PER_TASK][41]; 275 | char TaskDeviceValueNames[VARS_PER_TASK][41]; 276 | long TaskDevicePluginConfigLong[PLUGIN_EXTRACONFIGVAR_MAX]; 277 | byte TaskDeviceValueDecimals[VARS_PER_TASK]; 278 | } ExtraTaskSettings; 279 | 280 | struct EventStruct 281 | { 282 | byte Source; 283 | byte TaskIndex; 284 | byte BaseVarIndex; 285 | int idx; 286 | byte sensorType; 287 | int Par1; 288 | int Par2; 289 | int Par3; 290 | byte OriginTaskIndex; 291 | String String1; 292 | String String2; 293 | byte *Data; 294 | }; 295 | 296 | struct DeviceStruct 297 | { 298 | byte Number; 299 | byte Type; 300 | byte VType; 301 | byte Ports; 302 | boolean PullUpOption; 303 | boolean InverseLogicOption; 304 | boolean FormulaOption; 305 | byte ValueCount; 306 | boolean Custom; 307 | boolean SendDataOption; 308 | boolean GlobalSyncOption; 309 | boolean TimerOption; 310 | boolean TimerOptional; 311 | boolean DecimalsOnly; 312 | } Device[DEVICES_MAX + 1]; // 1 more because first device is empty device 313 | 314 | struct ProtocolStruct 315 | { 316 | byte Number; 317 | boolean usesMQTT; 318 | boolean usesAccount; 319 | boolean usesPassword; 320 | int defaultPort; 321 | boolean usesTemplate; 322 | } Protocol[CPLUGIN_MAX]; 323 | 324 | struct NodeStruct 325 | { 326 | byte ip[4]; 327 | byte age; 328 | uint16_t build; 329 | #if FEATURE_NODELIST_NAMES 330 | char nodeName[FEATURE_NODELIST_NAMESSIZE+1]; 331 | #endif 332 | byte nodeType; 333 | } Nodes[UNIT_MAX]; 334 | 335 | struct systemTimerStruct 336 | { 337 | unsigned long timer; 338 | byte plugin; 339 | byte Par1; 340 | byte Par2; 341 | byte Par3; 342 | } systemTimers[SYSTEM_TIMER_MAX]; 343 | 344 | struct systemCMDTimerStruct 345 | { 346 | unsigned long timer; 347 | String action; 348 | } systemCMDTimers[SYSTEM_CMD_TIMER_MAX]; 349 | 350 | struct pinStatesStruct 351 | { 352 | byte plugin; 353 | byte index; 354 | byte mode; 355 | uint16_t value; 356 | } pinStates[PINSTATE_TABLE_MAX]; 357 | 358 | int deviceCount = -1; 359 | int protocolCount = -1; 360 | 361 | boolean printToWeb = false; 362 | String printWebString = ""; 363 | boolean printToWebJSON = false; 364 | 365 | float UserVar[VARS_PER_TASK * TASKS_MAX]; 366 | unsigned long RulesTimer[RULES_TIMER_MAX]; 367 | 368 | unsigned long timerSensor[TASKS_MAX]; 369 | unsigned long timer; 370 | unsigned long timer100ms; 371 | unsigned long timer1s; 372 | unsigned long timerwd; 373 | unsigned long lastSend; 374 | byte cmd_within_mainloop = 0; 375 | unsigned long connectionFailures; 376 | unsigned long wdcounter = 0; 377 | 378 | boolean WebLoggedIn = false; 379 | int WebLoggedInTimer = 300; 380 | 381 | boolean (*Plugin_ptr[PLUGIN_MAX])(byte, struct EventStruct*, String&); 382 | byte Plugin_id[PLUGIN_MAX]; 383 | 384 | boolean (*CPlugin_ptr[CPLUGIN_MAX])(byte, struct EventStruct*, String&); 385 | byte CPlugin_id[CPLUGIN_MAX]; 386 | 387 | String dummyString = ""; 388 | 389 | boolean systemOK = false; 390 | 391 | unsigned long start = 0; 392 | unsigned long elapsed = 0; 393 | unsigned long loopCounter = 0; 394 | unsigned long loopCounterLast = 0; 395 | unsigned long loopCounterMax = 1; 396 | 397 | unsigned long flashWrites = 0; 398 | 399 | String eventBuffer = ""; 400 | 401 | int freeMem; 402 | 403 | /*********************************************************************************************\ 404 | * SETUP 405 | \*********************************************************************************************/ 406 | void setup() 407 | { 408 | Serial.begin(115200); 409 | 410 | fileSystemCheck(); 411 | 412 | emergencyReset(); 413 | 414 | LoadSettings(); 415 | 416 | ExtraTaskSettings.TaskIndex = 255; // make sure this is an unused nr to prevent cache load on boot 417 | 418 | // if different version, eeprom settings structure has changed. Full Reset needed 419 | // on a fresh ESP module eeprom values are set to 255. Version results into -1 (signed int) 420 | if (Settings.Version == VERSION && Settings.PID == ARDUINO_PROJECT_PID) 421 | { 422 | systemOK = true; 423 | } 424 | else 425 | { 426 | // Direct Serial is allowed here, since this is only an emergency task. 427 | Serial.print(F("\nPID:")); 428 | Serial.println(Settings.PID); 429 | Serial.print(F("Version:")); 430 | Serial.println(Settings.Version); 431 | Serial.println(F("INIT : Incorrect PID or version!")); 432 | delay(1000); 433 | ResetFactory(); 434 | } 435 | 436 | if (systemOK) 437 | { 438 | if (Settings.UseSerial) 439 | Serial.begin(Settings.BaudRate); 440 | 441 | if (Settings.Build != BUILD) 442 | BuildFixes(); 443 | 444 | mac[5] = Settings.Unit; // make sure every unit has a unique mac address 445 | if (Settings.IP[0] == 0) 446 | Ethernet.begin(mac); 447 | else 448 | Ethernet.begin(mac, Settings.IP, Settings.DNS, Settings.Gateway, Settings.Subnet); 449 | 450 | // setup UDP 451 | if (Settings.UDPPort != 0) 452 | portUDP.begin(Settings.UDPPort); 453 | else 454 | portUDP.begin(123); // setup for NTP and other stuff if no user port is selected 455 | 456 | hardwareInit(); 457 | PluginInit(); 458 | CPluginInit(); 459 | 460 | MyWebServer.begin(); 461 | 462 | #if FEATURE_MQTT 463 | // Setup MQTT Client 464 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 465 | if (Protocol[ProtocolIndex].usesMQTT) 466 | MQTTConnect(); 467 | #endif 468 | 469 | String log = F("\nINIT : Booting Build nr:"); 470 | log += BUILD; 471 | addLog(LOG_LEVEL_INFO, log); 472 | 473 | sendSysInfoUDP(3); 474 | 475 | // Setup timers 476 | byte bootMode = 0; 477 | if (bootMode == 0) 478 | { 479 | for (byte x = 0; x < TASKS_MAX; x++) 480 | if (Settings.TaskDeviceTimer[x] !=0) 481 | timerSensor[x] = millis() + 30000 + (x * Settings.MessageDelay); 482 | 483 | timer = millis() + 30000; // startup delay 30 sec 484 | } 485 | else 486 | { 487 | for (byte x = 0; x < TASKS_MAX; x++) 488 | timerSensor[x] = millis() + 0; 489 | timer = millis() + 0; // no startup from deepsleep wake up 490 | } 491 | 492 | timer100ms = millis() + 100; // timer for periodic actions 10 x per/sec 493 | timer1s = millis() + 1000; // timer for periodic actions once per/sec 494 | timerwd = millis() + 30000; // timer for watchdog once per 30 sec 495 | 496 | if (Settings.UseNTP) 497 | initTime(); 498 | 499 | if (Settings.UseRules) 500 | { 501 | String event = F("System#Boot"); 502 | rulesProcessing(event); 503 | } 504 | 505 | log = F("INIT : Boot OK"); 506 | addLog(LOG_LEVEL_INFO, log); 507 | #if socketdebug 508 | ShowSocketStatus(); 509 | #endif 510 | 511 | } 512 | else 513 | { 514 | Serial.println(F("Entered Rescue mode!")); 515 | } 516 | } 517 | 518 | 519 | /*********************************************************************************************\ 520 | * MAIN LOOP 521 | \*********************************************************************************************/ 522 | void loop() 523 | { 524 | loopCounter++; 525 | 526 | if (Settings.UseSerial) 527 | if (Serial.available()) 528 | if (!PluginCall(PLUGIN_SERIAL_IN, 0, dummyString)) 529 | serial(); 530 | 531 | if (systemOK) 532 | { 533 | if (millis() > timer100ms) 534 | run10TimesPerSecond(); 535 | 536 | if (millis() > timer1s) 537 | runOncePerSecond(); 538 | 539 | if (millis() > timerwd) 540 | runEach30Seconds(); 541 | 542 | backgroundtasks(); 543 | 544 | } 545 | else 546 | delay(1); 547 | } 548 | 549 | 550 | /*********************************************************************************************\ 551 | * Tasks that run 10 times per second 552 | \*********************************************************************************************/ 553 | void run10TimesPerSecond() 554 | { 555 | start = micros(); 556 | timer100ms = millis() + 100; 557 | PluginCall(PLUGIN_TEN_PER_SECOND, 0, dummyString); 558 | checkUDP(); 559 | if (Settings.UseRules && eventBuffer.length() > 0) 560 | { 561 | rulesProcessing(eventBuffer); 562 | eventBuffer = ""; 563 | } 564 | elapsed = micros() - start; 565 | } 566 | 567 | 568 | /*********************************************************************************************\ 569 | * Tasks each second 570 | \*********************************************************************************************/ 571 | void runOncePerSecond() 572 | { 573 | freeMem = FreeMem(); 574 | 575 | timer1s = millis() + 1000; 576 | 577 | checkSensors(); 578 | 579 | if (Settings.ConnectionFailuresThreshold) 580 | if (connectionFailures > Settings.ConnectionFailuresThreshold) 581 | delayedReboot(60); 582 | 583 | if (cmd_within_mainloop != 0) 584 | { 585 | switch (cmd_within_mainloop) 586 | { 587 | case CMD_REBOOT: 588 | { 589 | Reboot(); 590 | break; 591 | } 592 | } 593 | cmd_within_mainloop = 0; 594 | } 595 | 596 | // clock events 597 | if (Settings.UseNTP) 598 | checkTime(); 599 | 600 | unsigned long timer = micros(); 601 | PluginCall(PLUGIN_ONCE_A_SECOND, 0, dummyString); 602 | 603 | checkSystemTimers(); 604 | 605 | if (Settings.UseRules) 606 | rulesTimers(); 607 | 608 | timer = micros() - timer; 609 | 610 | if (SecuritySettings.Password[0] != 0) 611 | { 612 | if (WebLoggedIn) 613 | WebLoggedInTimer++; 614 | if (WebLoggedInTimer > 300) 615 | WebLoggedIn = false; 616 | } 617 | 618 | // I2C Watchdog feed 619 | if (Settings.WDI2CAddress != 0) 620 | { 621 | Wire.beginTransmission(Settings.WDI2CAddress); 622 | Wire.write(0xA5); 623 | Wire.endTransmission(); 624 | } 625 | 626 | if (Settings.SerialLogLevel == 5) 627 | { 628 | Serial.print(F("10 ps:")); 629 | Serial.print(elapsed); 630 | Serial.print(F(" uS 1 ps:")); 631 | Serial.println(timer); 632 | } 633 | } 634 | 635 | /*********************************************************************************************\ 636 | * Tasks each 30 seconds 637 | \*********************************************************************************************/ 638 | void runEach30Seconds() 639 | { 640 | wdcounter++; 641 | timerwd = millis() + 30000; 642 | String log = F("WD : Uptime "); 643 | log += wdcounter / 2; 644 | log += F(" ConnectFailures "); 645 | log += connectionFailures; 646 | log += F(" Freemem "); 647 | log += FreeMem(); 648 | addLog(LOG_LEVEL_INFO, log); 649 | sendSysInfoUDP(1); 650 | refreshNodeList(); 651 | loopCounterLast = loopCounter; 652 | loopCounter = 0; 653 | if (loopCounterLast > loopCounterMax) 654 | loopCounterMax = loopCounterLast; 655 | 656 | } 657 | 658 | 659 | /*********************************************************************************************\ 660 | * Check sensor timers 661 | \*********************************************************************************************/ 662 | void checkSensors() 663 | { 664 | for (byte x = 0; x < TASKS_MAX; x++) 665 | { 666 | if ((Settings.TaskDeviceTimer[x] != 0) && (millis() > timerSensor[x])) 667 | { 668 | timerSensor[x] = millis() + Settings.TaskDeviceTimer[x] * 1000; 669 | if (timerSensor[x] == 0) // small fix if result is 0, else timer will be stopped... 670 | timerSensor[x] = 1; 671 | SensorSendTask(x); 672 | } 673 | } 674 | } 675 | 676 | 677 | /*********************************************************************************************\ 678 | * send all sensordata 679 | \*********************************************************************************************/ 680 | void SensorSend() 681 | { 682 | for (byte x = 0; x < TASKS_MAX; x++) 683 | { 684 | SensorSendTask(x); 685 | } 686 | } 687 | 688 | 689 | /*********************************************************************************************\ 690 | * send specific sensor task data 691 | \*********************************************************************************************/ 692 | void SensorSendTask(byte TaskIndex) 693 | { 694 | if (Settings.TaskDeviceID[TaskIndex] != 0) 695 | { 696 | byte varIndex = TaskIndex * VARS_PER_TASK; 697 | 698 | boolean success = false; 699 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[TaskIndex]); 700 | LoadTaskSettings(TaskIndex); 701 | 702 | struct EventStruct TempEvent; 703 | TempEvent.TaskIndex = TaskIndex; 704 | TempEvent.BaseVarIndex = varIndex; 705 | TempEvent.idx = Settings.TaskDeviceID[TaskIndex]; 706 | TempEvent.sensorType = Device[DeviceIndex].VType; 707 | 708 | float preValue[VARS_PER_TASK]; // store values before change, in case we need it in the formula 709 | for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) 710 | preValue[varNr] = UserVar[varIndex + varNr]; 711 | 712 | if(Settings.TaskDeviceDataFeed[TaskIndex] == 0) // only read local connected sensorsfeeds 713 | success = PluginCall(PLUGIN_READ, &TempEvent, dummyString); 714 | else 715 | success = true; 716 | 717 | if (success) 718 | { 719 | for (byte varNr = 0; varNr < VARS_PER_TASK; varNr++) 720 | { 721 | if (ExtraTaskSettings.TaskDeviceFormula[varNr][0] != 0) 722 | { 723 | String spreValue = String(preValue[varNr]); 724 | String formula = ExtraTaskSettings.TaskDeviceFormula[varNr]; 725 | float value = UserVar[varIndex + varNr]; 726 | float result = 0; 727 | String svalue = String(value); 728 | formula.replace(F("%pvalue%"), spreValue); 729 | formula.replace(F("%value%"), svalue); 730 | byte error = Calculate(formula.c_str(), &result); 731 | if (error == 0) 732 | UserVar[varIndex + varNr] = result; 733 | } 734 | } 735 | sendData(&TempEvent); 736 | } 737 | } 738 | } 739 | 740 | 741 | /*********************************************************************************************\ 742 | * set global system timer 743 | \*********************************************************************************************/ 744 | boolean setSystemTimer(unsigned long timer, byte plugin, byte Par1, byte Par2, byte Par3) 745 | { 746 | // plugin number and par1 form a unique key that can be used to restart a timer 747 | // first check if a timer is not already running for this request 748 | boolean reUse = false; 749 | for (byte x = 0; x < SYSTEM_TIMER_MAX; x++) 750 | if (systemTimers[x].timer != 0) 751 | { 752 | if ((systemTimers[x].plugin == plugin) && (systemTimers[x].Par1 == Par1)) 753 | { 754 | systemTimers[x].timer = millis() + timer; 755 | reUse = true; 756 | break; 757 | } 758 | } 759 | 760 | if (!reUse) 761 | { 762 | // find a new free timer slot... 763 | for (byte x = 0; x < SYSTEM_TIMER_MAX; x++) 764 | if (systemTimers[x].timer == 0) 765 | { 766 | systemTimers[x].timer = millis() + timer; 767 | systemTimers[x].plugin = plugin; 768 | systemTimers[x].Par1 = Par1; 769 | systemTimers[x].Par2 = Par2; 770 | systemTimers[x].Par3 = Par3; 771 | break; 772 | } 773 | } 774 | } 775 | 776 | 777 | /*********************************************************************************************\ 778 | * set global system command timer 779 | \*********************************************************************************************/ 780 | boolean setSystemCMDTimer(unsigned long timer, String& action) 781 | { 782 | for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++) 783 | if (systemCMDTimers[x].timer == 0) 784 | { 785 | systemCMDTimers[x].timer = millis() + timer; 786 | systemCMDTimers[x].action = action; 787 | break; 788 | } 789 | } 790 | 791 | 792 | /*********************************************************************************************\ 793 | * check global system timers 794 | \*********************************************************************************************/ 795 | boolean checkSystemTimers() 796 | { 797 | for (byte x = 0; x < SYSTEM_TIMER_MAX; x++) 798 | if (systemTimers[x].timer != 0) 799 | { 800 | if (timeOut(systemTimers[x].timer)) 801 | { 802 | struct EventStruct TempEvent; 803 | TempEvent.Par1 = systemTimers[x].Par1; 804 | TempEvent.Par2 = systemTimers[x].Par2; 805 | TempEvent.Par3 = systemTimers[x].Par3; 806 | for (byte y = 0; y < PLUGIN_MAX; y++) 807 | if (Plugin_id[y] == systemTimers[x].plugin) 808 | Plugin_ptr[y](PLUGIN_TIMER_IN, &TempEvent, dummyString); 809 | systemTimers[x].timer = 0; 810 | } 811 | } 812 | 813 | for (byte x = 0; x < SYSTEM_CMD_TIMER_MAX; x++) 814 | if (systemCMDTimers[x].timer != 0) 815 | if (timeOut(systemCMDTimers[x].timer)) 816 | { 817 | struct EventStruct TempEvent; 818 | parseCommandString(&TempEvent, systemCMDTimers[x].action); 819 | if (!PluginCall(PLUGIN_WRITE, &TempEvent, systemCMDTimers[x].action)) 820 | ExecuteCommand(VALUE_SOURCE_SYSTEM, systemCMDTimers[x].action.c_str()); 821 | systemCMDTimers[x].timer = 0; 822 | systemCMDTimers[x].action = ""; 823 | } 824 | } 825 | 826 | 827 | /*********************************************************************************************\ 828 | * run background tasks 829 | \*********************************************************************************************/ 830 | void backgroundtasks() 831 | { 832 | WebServerHandleClient(); 833 | #if FEATURE_MQTT 834 | MQTTclient.loop(); 835 | #endif 836 | statusLED(false); 837 | checkUDP(); 838 | } 839 | 840 | -------------------------------------------------------------------------------- /src/Command.ino: -------------------------------------------------------------------------------- 1 | #define INPUT_COMMAND_SIZE 80 2 | void ExecuteCommand(byte source, const char *Line) 3 | { 4 | String status = ""; 5 | boolean success = false; 6 | char TmpStr1[80]; 7 | TmpStr1[0] = 0; 8 | char Command[80]; 9 | Command[0] = 0; 10 | int Par1 = 0; 11 | int Par2 = 0; 12 | int Par3 = 0; 13 | 14 | GetArgv(Line, Command, 1); 15 | if (GetArgv(Line, TmpStr1, 2)) Par1 = str2int(TmpStr1); 16 | if (GetArgv(Line, TmpStr1, 3)) Par2 = str2int(TmpStr1); 17 | if (GetArgv(Line, TmpStr1, 4)) Par3 = str2int(TmpStr1); 18 | 19 | // **************************************** 20 | // commands for debugging 21 | // **************************************** 22 | 23 | if (strcasecmp_P(Command, PSTR("w5100")) == 0) 24 | { 25 | success = true; 26 | ShowSocketStatus(); 27 | } 28 | 29 | if (strcasecmp_P(Command, PSTR("ntp")) == 0) 30 | { 31 | success = true; 32 | getNtpTime(); 33 | } 34 | 35 | if (strcasecmp_P(Command, PSTR("sdcard")) == 0) 36 | { 37 | success = true; 38 | SelectSDCard(true); 39 | File root = SD.open("/"); 40 | root.rewindDirectory(); 41 | printDirectory(root, 0); 42 | root.close(); 43 | } 44 | 45 | if (strcasecmp_P(Command, PSTR("sysload")) == 0) 46 | { 47 | success = true; 48 | Serial.print(100 - (100 * loopCounterLast / loopCounterMax)); 49 | Serial.print(F("% (LC=")); 50 | Serial.print(int(loopCounterLast / 30)); 51 | Serial.println(F(")")); 52 | } 53 | 54 | if (strcasecmp_P(Command, PSTR("meminfo")) == 0) 55 | { 56 | success = true; 57 | Serial.print(F("SecurityStruct : ")); 58 | Serial.println(sizeof(SecuritySettings)); 59 | Serial.print(F("SettingsStruct : ")); 60 | Serial.println(sizeof(Settings)); 61 | Serial.print(F("ExtraTaskSettingsStruct: ")); 62 | Serial.println(sizeof(ExtraTaskSettings)); 63 | } 64 | 65 | if (strcasecmp_P(Command, PSTR("TaskClear")) == 0) 66 | { 67 | success = true; 68 | taskClear(Par1 - 1, true); 69 | } 70 | 71 | if (strcasecmp_P(Command, PSTR("build")) == 0) 72 | { 73 | success = true; 74 | Settings.Build = Par1; 75 | SaveSettings(); 76 | } 77 | 78 | // **************************************** 79 | // commands for rules 80 | // **************************************** 81 | 82 | if (strcasecmp_P(Command, PSTR("TaskValueSet")) == 0) 83 | { 84 | success = true; 85 | if (GetArgv(Line, TmpStr1, 4)) 86 | { 87 | float result = 0; 88 | byte error = Calculate(TmpStr1, &result); 89 | UserVar[(VARS_PER_TASK * (Par1 - 1)) + Par2 - 1] = result; 90 | } 91 | } 92 | 93 | if (strcasecmp_P(Command, PSTR("TaskRun")) == 0) 94 | { 95 | success = true; 96 | SensorSendTask(Par1 -1); 97 | } 98 | 99 | if (strcasecmp_P(Command, PSTR("TimerSet")) == 0) 100 | { 101 | success = true; 102 | RulesTimer[Par1 - 1] = millis() + (1000 * Par2); 103 | } 104 | 105 | if (strcasecmp_P(Command, PSTR("Delay")) == 0) 106 | { 107 | success = true; 108 | delayMillis(Par1); 109 | } 110 | 111 | if (strcasecmp_P(Command, PSTR("Rules")) == 0) 112 | { 113 | success = true; 114 | if (Par1 == 1) 115 | Settings.UseRules = true; 116 | else 117 | Settings.UseRules = false; 118 | } 119 | 120 | if (strcasecmp_P(Command, PSTR("Event")) == 0) 121 | { 122 | success = true; 123 | String event = Line; 124 | event = event.substring(6); 125 | event.replace("$", "#"); 126 | if (Settings.UseRules) 127 | rulesProcessing(event); 128 | } 129 | 130 | if (strcasecmp_P(Command, PSTR("SendTo")) == 0) 131 | { 132 | success = true; 133 | String event = Line; 134 | event = event.substring(7); 135 | int index = event.indexOf(','); 136 | if (index > 0) 137 | { 138 | event = event.substring(index+1); 139 | SendUDPCommand(Par1, (char*)event.c_str(), event.length()); 140 | } 141 | } 142 | 143 | if (strcasecmp_P(Command, PSTR("SendToUDP")) == 0) 144 | { 145 | success = true; 146 | String strLine = Line; 147 | String ip = parseString(strLine,2); 148 | String port = parseString(strLine,3); 149 | int msgpos = getParamStartPos(strLine,4); 150 | String message = strLine.substring(msgpos); 151 | byte ipaddress[4]; 152 | str2ip((char*)ip.c_str(), ipaddress); 153 | IPAddress UDP_IP(ipaddress[0], ipaddress[1], ipaddress[2], ipaddress[3]); 154 | portUDP.beginPacket(UDP_IP, port.toInt()); 155 | portUDP.write(message.c_str(), message.length()); 156 | portUDP.endPacket(); 157 | } 158 | 159 | if (strcasecmp_P(Command, PSTR("SendToHTTP")) == 0) 160 | { 161 | success = true; 162 | String strLine = Line; 163 | String host = parseString(strLine,2); 164 | String port = parseString(strLine,3); 165 | int pathpos = getParamStartPos(strLine,4); 166 | String path = strLine.substring(pathpos); 167 | EthernetClient client; 168 | if (client.connect(host.c_str(), port.toInt())) 169 | { 170 | String request = F("GET "); 171 | request += path; 172 | request += F(" HTTP/1.1\r\n"); 173 | request += F("Host: "); 174 | request += host; 175 | request += F("\r\n"); 176 | // request += authHeader; 177 | request += F("Connection: close\r\n\r\n"); 178 | client.print(request); 179 | 180 | unsigned long timer = millis() + 200; 181 | while (!client.available() && millis() < timer) 182 | delay(1); 183 | 184 | while (client.available()) { 185 | String line = client.readStringUntil('\n'); 186 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 187 | addLog(LOG_LEVEL_DEBUG, line); 188 | delay(1); 189 | } 190 | client.flush(); 191 | client.stop(); 192 | } 193 | } 194 | 195 | // **************************************** 196 | // configure settings commands 197 | // **************************************** 198 | 199 | if (strcasecmp_P(Command, PSTR("Reboot")) == 0) 200 | { 201 | success = true; 202 | Reboot(); 203 | } 204 | 205 | if (strcasecmp_P(Command, PSTR("Restart")) == 0) 206 | { 207 | success = true; 208 | Reboot(); 209 | } 210 | 211 | if (strcasecmp_P(Command, PSTR("Reset")) == 0) 212 | { 213 | success = true; 214 | ResetFactory(); 215 | } 216 | 217 | if (strcasecmp_P(Command, PSTR("Save")) == 0) 218 | { 219 | success = true; 220 | SaveSettings(); 221 | } 222 | 223 | if (strcasecmp_P(Command, PSTR("Load")) == 0) 224 | { 225 | success = true; 226 | LoadSettings(); 227 | } 228 | 229 | if (strcasecmp_P(Command, PSTR("Debug")) == 0) 230 | { 231 | success = true; 232 | Settings.SerialLogLevel = Par1; 233 | } 234 | 235 | if (strcasecmp_P(Command, PSTR("IP")) == 0) 236 | { 237 | success = true; 238 | if (GetArgv(Line, TmpStr1, 2)) 239 | if (!str2ip(TmpStr1, Settings.IP)) 240 | Serial.println("?"); 241 | } 242 | 243 | if (strcasecmp_P(Command, PSTR("Settings")) == 0) 244 | { 245 | success = true; 246 | char str[20]; 247 | Serial.println(); 248 | 249 | Serial.println(F("System Info")); 250 | IPAddress ip = Ethernet.localIP(); 251 | sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); 252 | Serial.print(F(" IP Address : ")); Serial.println(str); 253 | Serial.print(F(" Build : ")); Serial.println((int)BUILD); 254 | Serial.print(F(" Unit : ")); Serial.println((int)Settings.Unit); 255 | Serial.print(F(" Free mem : ")); Serial.println(FreeMem()); 256 | } 257 | 258 | if (success) 259 | status += F("\nOk"); 260 | else 261 | status += F("\nUnknown command!"); 262 | SendStatus(source,status); 263 | } 264 | 265 | void printDirectory(File dir, int numTabs) { 266 | while(true) { 267 | 268 | File entry = dir.openNextFile(); 269 | if (! entry) { 270 | // no more files 271 | break; 272 | } 273 | for (uint8_t i=0; iTaskIndex); 7 | if (Settings.UseRules) 8 | createRuleEvents(event->TaskIndex); 9 | 10 | if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex]) 11 | SendUDPTaskData(0, event->TaskIndex, event->TaskIndex); 12 | 13 | if (!Settings.TaskDeviceSendData[event->TaskIndex]) 14 | return false; 15 | 16 | if (Settings.MessageDelay != 0) 17 | { 18 | uint16_t dif = millis() - lastSend; 19 | if (dif < Settings.MessageDelay) 20 | { 21 | uint16_t delayms = Settings.MessageDelay - dif; 22 | char log[30]; 23 | sprintf_P(log, PSTR("HTTP : Delay %u ms"), delayms); 24 | addLog(LOG_LEVEL_DEBUG_MORE, log); 25 | unsigned long timer = millis() + delayms; 26 | while (millis() < timer) 27 | backgroundtasks(); 28 | } 29 | } 30 | 31 | LoadTaskSettings(event->TaskIndex); // could have changed during background tasks. 32 | 33 | if (Settings.Protocol) 34 | { 35 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 36 | CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString); 37 | } 38 | PluginCall(PLUGIN_EVENT_OUT, event, dummyString); 39 | lastSend = millis(); 40 | } 41 | 42 | /*********************************************************************************************\ 43 | * Send status info to request source 44 | \*********************************************************************************************/ 45 | 46 | void SendStatus(byte source, String status) 47 | { 48 | switch(source) 49 | { 50 | case VALUE_SOURCE_HTTP: 51 | if (printToWeb) 52 | printWebString += status; 53 | break; 54 | case VALUE_SOURCE_SERIAL: 55 | Serial.println(status); 56 | break; 57 | } 58 | } 59 | 60 | 61 | #if FEATURE_MQTT 62 | /*********************************************************************************************\ 63 | * Handle incoming MQTT messages 64 | \*********************************************************************************************/ 65 | // handle MQTT messages 66 | void callback(char* c_topic, byte* b_payload, unsigned int length) { 67 | char c_payload[384]; 68 | strncpy(c_payload,(char*)b_payload,length); 69 | c_payload[length] = 0; 70 | statusLED(true); 71 | 72 | String log; 73 | log=F("MQTT : Topic: "); 74 | log+=c_topic; 75 | addLog(LOG_LEVEL_DEBUG, log); 76 | 77 | log=F("MQTT : Payload: "); 78 | log+=c_payload; 79 | addLog(LOG_LEVEL_DEBUG, log); 80 | 81 | struct EventStruct TempEvent; 82 | TempEvent.String1 = c_topic; 83 | TempEvent.String2 = c_payload; 84 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 85 | CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString); 86 | } 87 | 88 | 89 | /*********************************************************************************************\ 90 | * Connect to MQTT message broker 91 | \*********************************************************************************************/ 92 | void MQTTConnect() 93 | { 94 | IPAddress MQTTBrokerIP(Settings.Controller_IP); 95 | MQTTclient.setServer(MQTTBrokerIP, Settings.ControllerPort); 96 | MQTTclient.setCallback(callback); 97 | 98 | // MQTT needs a unique clientname to subscribe to broker 99 | String clientid = F("ESPClient"); 100 | clientid += Settings.Unit; 101 | String subscribeTo = ""; 102 | 103 | String LWTTopic = Settings.MQTTsubscribe; 104 | LWTTopic.replace(F("/#"), F("/status")); 105 | LWTTopic.replace(F("%sysname%"), Settings.Name); 106 | 107 | for (byte x = 1; x < 3; x++) 108 | { 109 | String log = ""; 110 | boolean MQTTresult = false; 111 | 112 | String msg = F("Connection Lost"); 113 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 114 | MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword, LWTTopic.c_str(), 0, 0, msg.c_str()); 115 | else 116 | MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, msg.c_str()); 117 | 118 | if (MQTTresult) 119 | { 120 | log = F("MQTT : Connected to broker"); 121 | addLog(LOG_LEVEL_INFO, log); 122 | subscribeTo = Settings.MQTTsubscribe; 123 | subscribeTo.replace(F("%sysname%"), Settings.Name); 124 | MQTTclient.subscribe(subscribeTo.c_str()); 125 | log = F("Subscribed to: "); 126 | log += subscribeTo; 127 | addLog(LOG_LEVEL_INFO, log); 128 | break; // end loop if succesfull 129 | } 130 | else 131 | { 132 | log = F("MQTT : Failed to connected to broker"); 133 | addLog(LOG_LEVEL_ERROR, log); 134 | } 135 | 136 | delay(500); 137 | } 138 | } 139 | 140 | 141 | /*********************************************************************************************\ 142 | * Check connection MQTT message broker 143 | \*********************************************************************************************/ 144 | void MQTTCheck() 145 | { 146 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 147 | if (Protocol[ProtocolIndex].usesMQTT) 148 | if (!MQTTclient.connected()) 149 | { 150 | String log = F("MQTT : Connection lost"); 151 | addLog(LOG_LEVEL_ERROR, log); 152 | connectionFailures += 2; 153 | MQTTclient.disconnect(); 154 | delay(1000); 155 | MQTTConnect(); 156 | } 157 | else if (connectionFailures) 158 | connectionFailures--; 159 | } 160 | 161 | 162 | /*********************************************************************************************\ 163 | * Send status info back to channel where request came from 164 | \*********************************************************************************************/ 165 | void MQTTStatus(String& status) 166 | { 167 | String pubname = Settings.MQTTsubscribe; 168 | pubname.replace(F("/#"), F("/status")); 169 | pubname.replace(F("%sysname%"), Settings.Name); 170 | MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag); 171 | } 172 | #endif 173 | 174 | -------------------------------------------------------------------------------- /src/Hardware.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************************************\ 2 | * Initialize specific hardware setings (only global ones, others are set through devices) 3 | \*********************************************************************************************/ 4 | 5 | void hardwareInit() 6 | { 7 | 8 | // set GPIO pins state if not set to default 9 | for (byte x=0; x < 17; x++) 10 | if (Settings.PinBootStates[x] != 0) 11 | switch(Settings.PinBootStates[x]) 12 | { 13 | case 1: 14 | pinMode(x,OUTPUT); 15 | digitalWrite(x,LOW); 16 | setPinState(1, x, PIN_MODE_OUTPUT, LOW); 17 | break; 18 | case 2: 19 | pinMode(x,OUTPUT); 20 | digitalWrite(x,HIGH); 21 | setPinState(1, x, PIN_MODE_OUTPUT, HIGH); 22 | break; 23 | case 3: 24 | pinMode(x,INPUT_PULLUP); 25 | setPinState(1, x, PIN_MODE_INPUT, 0); 26 | break; 27 | } 28 | 29 | String log = F("INIT : I2C"); 30 | addLog(LOG_LEVEL_INFO, log); 31 | Wire.begin(); 32 | 33 | // I2C Watchdog boot status check 34 | if (Settings.WDI2CAddress != 0) 35 | { 36 | delay(500); 37 | Wire.beginTransmission(Settings.WDI2CAddress); 38 | Wire.write(0x83); // command to set pointer 39 | Wire.write(17); // pointer value to status byte 40 | Wire.endTransmission(); 41 | 42 | Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1); 43 | if (Wire.available()) 44 | { 45 | byte status = Wire.read(); 46 | if (status & 0x1) 47 | { 48 | String log = F("INIT : Reset by WD!"); 49 | addLog(LOG_LEVEL_ERROR, log); 50 | //lastBootCause = BOOT_CAUSE_EXT_WD; 51 | } 52 | } 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/Networking.ino: -------------------------------------------------------------------------------- 1 | /*********************************************************************************************\ 2 | Syslog client 3 | \*********************************************************************************************/ 4 | void syslog(const char *message) 5 | { 6 | if (Settings.Syslog_IP[0] != 0) 7 | { 8 | IPAddress broadcastIP(Settings.Syslog_IP[0], Settings.Syslog_IP[1], Settings.Syslog_IP[2], Settings.Syslog_IP[3]); 9 | portUDP.beginPacket(broadcastIP, 514); 10 | char str[256]; 11 | str[0] = 0; 12 | snprintf_P(str, sizeof(str), PSTR("<7>ESP Unit: %u : %s"), Settings.Unit, message); 13 | portUDP.write(str); 14 | portUDP.endPacket(); 15 | } 16 | } 17 | 18 | 19 | /*********************************************************************************************\ 20 | Structs for UDP messaging 21 | \*********************************************************************************************/ 22 | struct infoStruct 23 | { 24 | byte header = 255; 25 | byte ID = 3; 26 | byte sourcelUnit; 27 | byte destUnit; 28 | byte sourceTaskIndex; 29 | byte destTaskIndex; 30 | byte deviceNumber; 31 | char taskName[26]; 32 | char ValueNames[VARS_PER_TASK][26]; 33 | }; 34 | 35 | struct dataStruct 36 | { 37 | byte header = 255; 38 | byte ID = 5; 39 | byte sourcelUnit; 40 | byte destUnit; 41 | byte sourceTaskIndex; 42 | byte destTaskIndex; 43 | float Values[VARS_PER_TASK]; 44 | }; 45 | 46 | /*********************************************************************************************\ 47 | Check UDP messages 48 | \*********************************************************************************************/ 49 | void checkUDP() 50 | { 51 | if (Settings.UDPPort == 0) 52 | return; 53 | 54 | // UDP events 55 | int packetSize = portUDP.parsePacket(); 56 | if (packetSize) 57 | { 58 | statusLED(true); 59 | 60 | IPAddress remoteIP = portUDP.remoteIP(); 61 | if (portUDP.remotePort() == 123) 62 | { 63 | // unexpected NTP reply, drop for now... 64 | return; 65 | } 66 | byte packetBuffer[128]; 67 | int len = portUDP.read(packetBuffer, 128); 68 | if (packetBuffer[0] != 255) 69 | { 70 | packetBuffer[len] = 0; 71 | addLog(LOG_LEVEL_DEBUG, (char*)packetBuffer); 72 | struct EventStruct TempEvent; 73 | String request = (char*)packetBuffer; 74 | parseCommandString(&TempEvent, request); 75 | TempEvent.Source = VALUE_SOURCE_SYSTEM; 76 | if (!PluginCall(PLUGIN_WRITE, &TempEvent, request)) 77 | ExecuteCommand(VALUE_SOURCE_SYSTEM, (char*)packetBuffer); 78 | } 79 | else 80 | { 81 | if (packetBuffer[1] > 1 && packetBuffer[1] < 6) 82 | { 83 | String log = (F("UDP : Sensor msg ")); 84 | for (byte x = 1; x < 6; x++) 85 | { 86 | log += " "; 87 | log += (int)packetBuffer[x]; 88 | } 89 | addLog(LOG_LEVEL_DEBUG_MORE, log); 90 | } 91 | 92 | // binary data! 93 | switch (packetBuffer[1]) 94 | { 95 | case 1: // sysinfo message 96 | { 97 | byte mac[6]; 98 | byte ip[4]; 99 | byte unit = packetBuffer[12]; 100 | for (byte x = 0; x < 6; x++) 101 | mac[x] = packetBuffer[x + 2]; 102 | for (byte x = 0; x < 4; x++) 103 | ip[x] = packetBuffer[x + 8]; 104 | 105 | if (unit < UNIT_MAX) 106 | { 107 | for (byte x = 0; x < 4; x++) 108 | Nodes[unit].ip[x] = packetBuffer[x + 8]; 109 | Nodes[unit].age = 0; // reset 'age counter' 110 | if (len >20) // extended packet size 111 | { 112 | Nodes[unit].build = packetBuffer[13] + 256*packetBuffer[14]; 113 | #if FEATURE_NODELIST_NAMES 114 | //if (Nodes[unit].nodeName==0) 115 | // Nodes[unit].nodeName = (char *)malloc(FEATURE_NODELIST_NAMESSIZE+1); 116 | memcpy(&Nodes[unit].nodeName,(byte*)packetBuffer+15,FEATURE_NODELIST_NAMESSIZE); 117 | Nodes[unit].nodeName[FEATURE_NODELIST_NAMESSIZE]=0; 118 | Nodes[unit].nodeType = packetBuffer[40]; 119 | #endif 120 | } 121 | } 122 | 123 | char macaddress[20]; 124 | sprintf_P(macaddress, PSTR("%02x:%02x:%02x:%02x:%02x:%02x"), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 125 | char ipaddress[16]; 126 | sprintf_P(ipaddress, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); 127 | char log[80]; 128 | sprintf_P(log, PSTR("UDP : %s,%s,%u"), macaddress, ipaddress, unit); 129 | addLog(LOG_LEVEL_DEBUG_MORE, log); 130 | break; 131 | } 132 | 133 | case 2: // sensor info pull request 134 | { 135 | SendUDPTaskInfo(packetBuffer[2], packetBuffer[5], packetBuffer[4]); 136 | break; 137 | } 138 | 139 | case 3: // sensor info 140 | { 141 | if (Settings.GlobalSync) 142 | { 143 | struct infoStruct infoReply; 144 | memcpy((byte*)&infoReply, (byte*)&packetBuffer, sizeof(infoStruct)); 145 | 146 | // to prevent flash wear out (bugs in communication?) we can only write to an empty task 147 | // so it will write only once and has to be cleared manually through webgui 148 | if (Settings.TaskDeviceNumber[infoReply.destTaskIndex] == 0) 149 | { 150 | Settings.TaskDeviceNumber[infoReply.destTaskIndex] = infoReply.deviceNumber; 151 | Settings.TaskDeviceDataFeed[infoReply.destTaskIndex] = 1; // remote feed 152 | Settings.TaskDeviceSendData[infoReply.destTaskIndex] = false; 153 | strcpy(ExtraTaskSettings.TaskDeviceName, infoReply.taskName); 154 | for (byte x = 0; x < VARS_PER_TASK; x++) 155 | strcpy( ExtraTaskSettings.TaskDeviceValueNames[x], infoReply.ValueNames[x]); 156 | SaveTaskSettings(infoReply.destTaskIndex); 157 | SaveSettings(); 158 | } 159 | } 160 | break; 161 | } 162 | 163 | case 4: // sensor data pull request 164 | { 165 | SendUDPTaskData(packetBuffer[2], packetBuffer[5], packetBuffer[4]); 166 | break; 167 | } 168 | 169 | case 5: // sensor data 170 | { 171 | if (Settings.GlobalSync) 172 | { 173 | struct dataStruct dataReply; 174 | memcpy((byte*)&dataReply, (byte*)&packetBuffer, sizeof(dataStruct)); 175 | 176 | // only if this task has a remote feed, update values 177 | if (Settings.TaskDeviceDataFeed[dataReply.destTaskIndex] != 0) 178 | { 179 | for (byte x = 0; x < VARS_PER_TASK; x++) 180 | { 181 | UserVar[dataReply.destTaskIndex * VARS_PER_TASK + x] = dataReply.Values[x]; 182 | } 183 | if (Settings.UseRules) 184 | createRuleEvents(dataReply.destTaskIndex); 185 | } 186 | } 187 | break; 188 | } 189 | 190 | default: 191 | { 192 | struct EventStruct TempEvent; 193 | TempEvent.Data = (byte*)packetBuffer; 194 | TempEvent.Par1 = remoteIP[3]; 195 | PluginCall(PLUGIN_UDP_IN, &TempEvent, dummyString); 196 | break; 197 | } 198 | } 199 | } 200 | } 201 | } 202 | 203 | 204 | /*********************************************************************************************\ 205 | Send task info using UDP message 206 | \*********************************************************************************************/ 207 | void SendUDPTaskInfo(byte destUnit, byte sourceTaskIndex, byte destTaskIndex) 208 | { 209 | struct infoStruct infoReply; 210 | infoReply.sourcelUnit = Settings.Unit; 211 | infoReply.sourceTaskIndex = sourceTaskIndex; 212 | infoReply.destTaskIndex = destTaskIndex; 213 | LoadTaskSettings(infoReply.sourceTaskIndex); 214 | infoReply.deviceNumber = Settings.TaskDeviceNumber[infoReply.sourceTaskIndex]; 215 | strcpy(infoReply.taskName, ExtraTaskSettings.TaskDeviceName); 216 | for (byte x = 0; x < VARS_PER_TASK; x++) 217 | strcpy(infoReply.ValueNames[x], ExtraTaskSettings.TaskDeviceValueNames[x]); 218 | 219 | byte firstUnit = 1; 220 | byte lastUnit = UNIT_MAX - 1; 221 | if (destUnit != 0) 222 | { 223 | firstUnit = destUnit; 224 | lastUnit = destUnit; 225 | } 226 | for (byte x = firstUnit; x <= lastUnit; x++) 227 | { 228 | infoReply.destUnit = x; 229 | sendUDP(x, (byte*)&infoReply, sizeof(infoStruct)); 230 | delay(10); 231 | } 232 | delay(50); 233 | } 234 | 235 | 236 | /*********************************************************************************************\ 237 | Send task data using UDP message 238 | \*********************************************************************************************/ 239 | void SendUDPTaskData(byte destUnit, byte sourceTaskIndex, byte destTaskIndex) 240 | { 241 | struct dataStruct dataReply; 242 | dataReply.sourcelUnit = Settings.Unit; 243 | dataReply.sourceTaskIndex = sourceTaskIndex; 244 | dataReply.destTaskIndex = destTaskIndex; 245 | for (byte x = 0; x < VARS_PER_TASK; x++) 246 | dataReply.Values[x] = UserVar[dataReply.sourceTaskIndex * VARS_PER_TASK + x]; 247 | 248 | byte firstUnit = 1; 249 | byte lastUnit = UNIT_MAX - 1; 250 | if (destUnit != 0) 251 | { 252 | firstUnit = destUnit; 253 | lastUnit = destUnit; 254 | } 255 | for (byte x = firstUnit; x <= lastUnit; x++) 256 | { 257 | dataReply.destUnit = x; 258 | sendUDP(x, (byte*) &dataReply, sizeof(dataStruct)); 259 | delay(10); 260 | } 261 | delay(50); 262 | } 263 | 264 | 265 | /*********************************************************************************************\ 266 | Send event using UDP message 267 | \*********************************************************************************************/ 268 | void SendUDPCommand(byte destUnit, char* data, byte dataLength) 269 | { 270 | byte firstUnit = 1; 271 | byte lastUnit = UNIT_MAX - 1; 272 | if (destUnit != 0) 273 | { 274 | firstUnit = destUnit; 275 | lastUnit = destUnit; 276 | } 277 | for (byte x = firstUnit; x <= lastUnit; x++) 278 | { 279 | sendUDP(x, (byte*)data, dataLength); 280 | delay(10); 281 | } 282 | delay(50); 283 | } 284 | 285 | 286 | /*********************************************************************************************\ 287 | Send UDP message 288 | \*********************************************************************************************/ 289 | void sendUDP(byte unit, byte* data, byte size) 290 | { 291 | if (Nodes[unit].ip[0] == 0) 292 | return; 293 | String log = F("UDP : Send UDP message to "); 294 | log += unit; 295 | addLog(LOG_LEVEL_DEBUG_MORE, log); 296 | 297 | statusLED(true); 298 | 299 | IPAddress remoteNodeIP(Nodes[unit].ip[0], Nodes[unit].ip[1], Nodes[unit].ip[2], Nodes[unit].ip[3]); 300 | portUDP.beginPacket(remoteNodeIP, Settings.UDPPort); 301 | portUDP.write(data, size); 302 | portUDP.endPacket(); 303 | } 304 | 305 | 306 | /*********************************************************************************************\ 307 | Refresh aging for remote units, drop if too old... 308 | \*********************************************************************************************/ 309 | void refreshNodeList() 310 | { 311 | for (byte counter = 0; counter < UNIT_MAX; counter++) 312 | { 313 | if (Nodes[counter].ip[0] != 0) 314 | { 315 | Nodes[counter].age++; // increment age counter 316 | if (Nodes[counter].age > 10) // if entry to old, clear this node ip from the list. 317 | for (byte x = 0; x < 4; x++) 318 | Nodes[counter].ip[x] = 0; 319 | } 320 | } 321 | } 322 | 323 | void sendSysInfoUDP(byte repeats) 324 | { 325 | char log[80]; 326 | if (Settings.UDPPort == 0) 327 | return; 328 | 329 | // 1 byte 'binary token 255' 330 | // 1 byte id '1' 331 | // 6 byte mac 332 | // 4 byte ip 333 | // 1 byte unit 334 | // 2 byte build 335 | // 25 char name 336 | // 1 byte node type id 337 | 338 | // send my info to the world... 339 | strcpy_P(log, PSTR("UDP : Send Sysinfo message")); 340 | addLog(LOG_LEVEL_DEBUG_MORE, log); 341 | for (byte counter = 0; counter < repeats; counter++) 342 | { 343 | byte data[80]; 344 | data[0] = 255; 345 | data[1] = 1; 346 | for (byte x = 0; x < 6; x++) 347 | data[x + 2] = mac[x]; 348 | IPAddress ip = Ethernet.localIP(); 349 | for (byte x = 0; x < 4; x++) 350 | data[x + 8] = ip[x]; 351 | data[12] = Settings.Unit; 352 | data[13] = Settings.Build & 0xff; 353 | data[14] = Settings.Build >> 8; 354 | memcpy((byte*)data+15,Settings.Name,25); 355 | data[40] = NODE_TYPE_ID; 356 | statusLED(true); 357 | 358 | IPAddress broadcastIP(255, 255, 255, 255); 359 | portUDP.beginPacket(broadcastIP, Settings.UDPPort); 360 | portUDP.write(data, 80); 361 | portUDP.endPacket(); 362 | if (counter < (repeats - 1)) 363 | delay(500); 364 | } 365 | 366 | // store my own info also in the list... 367 | if (Settings.Unit < UNIT_MAX) 368 | { 369 | IPAddress ip = Ethernet.localIP(); 370 | for (byte x = 0; x < 4; x++) 371 | Nodes[Settings.Unit].ip[x] = ip[x]; 372 | Nodes[Settings.Unit].age = 0; 373 | Nodes[Settings.Unit].build = Settings.Build; 374 | Nodes[Settings.Unit].nodeType = NODE_TYPE_ID; 375 | } 376 | } 377 | 378 | -------------------------------------------------------------------------------- /src/Serial.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************************************\ 2 | * Get data from Serial Interface 3 | \*********************************************************************************************/ 4 | #define INPUT_BUFFER_SIZE 128 5 | 6 | byte SerialInByte; 7 | int SerialInByteCounter = 0; 8 | char InputBuffer_Serial[INPUT_BUFFER_SIZE + 2]; 9 | 10 | void serial() 11 | { 12 | while (Serial.available()) 13 | { 14 | SerialInByte = Serial.read(); 15 | if (SerialInByte == 255) // binary data... 16 | { 17 | Serial.flush(); 18 | return; 19 | } 20 | 21 | if (isprint(SerialInByte)) 22 | { 23 | if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits 24 | InputBuffer_Serial[SerialInByteCounter++] = SerialInByte; 25 | } 26 | 27 | if (SerialInByte == '\n') 28 | { 29 | InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed 30 | Serial.write('>'); 31 | Serial.println(InputBuffer_Serial); 32 | String action = InputBuffer_Serial; 33 | struct EventStruct TempEvent; 34 | parseCommandString(&TempEvent, action); 35 | TempEvent.Source = VALUE_SOURCE_SERIAL; 36 | if (!PluginCall(PLUGIN_WRITE, &TempEvent, action)) 37 | ExecuteCommand(VALUE_SOURCE_SERIAL, InputBuffer_Serial); 38 | SerialInByteCounter = 0; 39 | InputBuffer_Serial[0] = 0; // serial data processed, clear buffer 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/_C001.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 001: Domoticz HTTP ###################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_001 6 | #define CPLUGIN_ID_001 1 7 | #define CPLUGIN_NAME_001 "Domoticz HTTP" 8 | 9 | boolean CPlugin_001(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_001; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = true; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 8080; 22 | break; 23 | } 24 | 25 | case CPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(CPLUGIN_NAME_001); 28 | break; 29 | } 30 | 31 | case CPLUGIN_PROTOCOL_SEND: 32 | { 33 | String authHeader = ""; 34 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 35 | { 36 | base64 encoder; 37 | String auth = SecuritySettings.ControllerUser; 38 | auth += F(":"); 39 | auth += SecuritySettings.ControllerPassword; 40 | authHeader = F("Authorization: Basic "); 41 | authHeader += encoder.encode(auth); 42 | authHeader += F(" \r\n"); 43 | } 44 | 45 | char log[80]; 46 | boolean success = false; 47 | char host[20]; 48 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 49 | 50 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 51 | addLog(LOG_LEVEL_DEBUG, log); 52 | 53 | // Use WiFiClient class to create TCP connections 54 | EthernetClient client; 55 | if (!client.connect(host, Settings.ControllerPort)) 56 | { 57 | connectionFailures++; 58 | strcpy_P(log, PSTR("HTTP : connection failed")); 59 | addLog(LOG_LEVEL_ERROR, log); 60 | return false; 61 | } 62 | #if socketdebug 63 | ShowSocketStatus(); 64 | #endif 65 | statusLED(true); 66 | if (connectionFailures) 67 | connectionFailures--; 68 | 69 | // We now create a URI for the request 70 | String url = F("/json.htm?type=command¶m=udevice&idx="); 71 | url += event->idx; 72 | 73 | switch (event->sensorType) 74 | { 75 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 76 | url += F("&svalue="); 77 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 78 | break; 79 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 80 | url += F("&svalue="); 81 | url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 82 | break; 83 | case SENSOR_TYPE_DUAL: // any sensor that uses two simple values 84 | url += F("&svalue="); 85 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 86 | url += F(";"); 87 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 88 | break; 89 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 90 | url += F("&svalue="); 91 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 92 | url += F(";"); 93 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 94 | url += F(";0"); 95 | break; 96 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 97 | url += F("&svalue="); 98 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 99 | url += F(";0;0;"); 100 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 101 | url += F(";0"); 102 | break; 103 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 104 | url += F("&svalue="); 105 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 106 | url += F(";"); 107 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 108 | url += F(";0;"); 109 | url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 110 | url += ";0"; 111 | break; 112 | case SENSOR_TYPE_SWITCH: 113 | url = F("/json.htm?type=command¶m=switchlight&idx="); 114 | url += event->idx; 115 | url += F("&switchcmd="); 116 | if (UserVar[event->BaseVarIndex] == 0) 117 | url += F("Off"); 118 | else 119 | url += F("On"); 120 | break; 121 | case SENSOR_TYPE_DIMMER: 122 | url = F("/json.htm?type=command¶m=switchlight&idx="); 123 | url += event->idx; 124 | url += F("&switchcmd="); 125 | if (UserVar[event->BaseVarIndex] == 0) 126 | url += F("Off"); 127 | else 128 | { 129 | url += F("Set%20Level&level="); 130 | url += UserVar[event->BaseVarIndex]; 131 | } 132 | break; 133 | } 134 | 135 | url.toCharArray(log, 80); 136 | addLog(LOG_LEVEL_DEBUG_MORE, log); 137 | 138 | // This will send the request to the server 139 | String request = F("GET "); 140 | request += url; 141 | request += F(" HTTP/1.1\r\n"); 142 | request += F("Host: "); 143 | request += host; 144 | request += F("\r\n"); 145 | request += authHeader; 146 | request += F("Connection: close\r\n\r\n"); 147 | client.print(request); 148 | 149 | unsigned long timer = millis() + 200; 150 | while (!client.available() && millis() < timer) 151 | delay(1); 152 | 153 | // Read all the lines of the reply from server and print them to Serial 154 | while (client.available()) { 155 | String line = client.readStringUntil('\n'); 156 | line.toCharArray(log, 80); 157 | addLog(LOG_LEVEL_DEBUG_MORE, log); 158 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 159 | { 160 | strcpy_P(log, PSTR("HTTP : Success")); 161 | addLog(LOG_LEVEL_DEBUG, log); 162 | success = true; 163 | } 164 | delay(1); 165 | } 166 | strcpy_P(log, PSTR("HTTP : closing connection")); 167 | addLog(LOG_LEVEL_DEBUG, log); 168 | 169 | client.flush(); 170 | client.stop(); 171 | 172 | break; 173 | } 174 | 175 | } 176 | return success; 177 | } 178 | 179 | -------------------------------------------------------------------------------- /src/_C002.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 002: Domoticz MQTT ###################################### 3 | //####################################################################################################### 4 | 5 | #if FEATURE_MQTT_DOM 6 | #define CPLUGIN_002 7 | #define CPLUGIN_ID_002 2 8 | #define CPLUGIN_NAME_002 "Domoticz MQTT" 9 | 10 | boolean CPlugin_002(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | 14 | switch (function) 15 | { 16 | case CPLUGIN_PROTOCOL_ADD: 17 | { 18 | Protocol[++protocolCount].Number = CPLUGIN_ID_002; 19 | Protocol[protocolCount].usesMQTT = true; 20 | Protocol[protocolCount].usesTemplate = true; 21 | Protocol[protocolCount].usesAccount = true; 22 | Protocol[protocolCount].usesPassword = true; 23 | Protocol[protocolCount].defaultPort = 1883; 24 | break; 25 | } 26 | 27 | case CPLUGIN_GET_DEVICENAME: 28 | { 29 | string = F(CPLUGIN_NAME_002); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_TEMPLATE: 34 | { 35 | strcpy_P(Settings.MQTTsubscribe, PSTR("domoticz/out")); 36 | strcpy_P(Settings.MQTTpublish, PSTR("domoticz/in")); 37 | break; 38 | } 39 | 40 | case CPLUGIN_PROTOCOL_RECV: 41 | { 42 | char json[512]; 43 | json[0] = 0; 44 | event->String2.toCharArray(json, 512); 45 | 46 | StaticJsonBuffer<512> jsonBuffer; 47 | JsonObject& root = jsonBuffer.parseObject(json); 48 | 49 | if (root.success()) 50 | { 51 | long idx = root[F("idx")]; 52 | float nvalue = root[F("nvalue")]; 53 | long nvaluealt = root[F("nvalue")]; 54 | //const char* name = root["name"]; // Not used 55 | //const char* svalue = root["svalue"]; // Not used 56 | const char* svalue1 = root[F("svalue1")]; 57 | //const char* svalue2 = root["svalue2"]; // Not used 58 | //const char* svalue3 = root["svalue3"]; // Not used 59 | const char* switchtype = root[F("switchType")]; // Expect "On/Off" or "dimmer" 60 | if (nvalue == 0) 61 | nvalue = nvaluealt; 62 | if ((int)switchtype == 0) 63 | switchtype = "?"; 64 | 65 | for (byte x = 0; x < TASKS_MAX; x++) 66 | { 67 | if (Settings.TaskDeviceID[x] == idx) 68 | { 69 | if (Settings.TaskDeviceNumber[x] == 1) // temp solution, if input switch, update state 70 | { 71 | String action = F("inputSwitchState,"); 72 | action += x; 73 | action += F(","); 74 | action += nvalue; 75 | struct EventStruct TempEvent; 76 | parseCommandString(&TempEvent, action); 77 | PluginCall(PLUGIN_WRITE, &TempEvent, action); 78 | } 79 | if (Settings.TaskDeviceNumber[x] == 29) // temp solution, if plugin 029, set gpio 80 | { 81 | String action = ""; 82 | int baseVar = x * VARS_PER_TASK; 83 | struct EventStruct TempEvent; 84 | if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0) 85 | { 86 | int pwmValue = UserVar[baseVar]; 87 | action = F("pwm,"); 88 | action += Settings.TaskDevicePin1[x]; 89 | action += F(","); 90 | switch ((int)nvalue) 91 | { 92 | case 0: 93 | pwmValue = 0; 94 | break; 95 | case 1: 96 | pwmValue = UserVar[baseVar]; 97 | break; 98 | case 2: 99 | pwmValue = 10 * atol(svalue1); 100 | UserVar[baseVar] = pwmValue; 101 | break; 102 | } 103 | action += pwmValue; 104 | } 105 | else 106 | { 107 | UserVar[baseVar] = nvalue; 108 | action = F("gpio,"); 109 | action += Settings.TaskDevicePin1[x]; 110 | action += F(","); 111 | action += nvalue; 112 | } 113 | parseCommandString(&TempEvent, action); 114 | PluginCall(PLUGIN_WRITE, &TempEvent, action); 115 | } 116 | } 117 | } 118 | } 119 | break; 120 | } 121 | 122 | case CPLUGIN_PROTOCOL_SEND: 123 | { 124 | StaticJsonBuffer<200> jsonBuffer; 125 | 126 | JsonObject& root = jsonBuffer.createObject(); 127 | 128 | root["idx"] = event->idx; 129 | 130 | String values; 131 | char str[80]; 132 | 133 | switch (event->sensorType) 134 | { 135 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 136 | root[F("nvalue")] = 0; 137 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 138 | values.toCharArray(str, 80); 139 | root[F("svalue")] = str; 140 | break; 141 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 142 | root[F("nvalue")] = 0; 143 | values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 144 | values.toCharArray(str, 80); 145 | root[F("svalue")] = str; 146 | break; 147 | case SENSOR_TYPE_DUAL: // any sensor that uses two simple values 148 | root[F("nvalue")] = 0; 149 | values = toString(UserVar[event->BaseVarIndex ],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 150 | values += ";"; 151 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 152 | values.toCharArray(str, 80); 153 | root[F("svalue")] = str; 154 | break; 155 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 156 | root[F("nvalue")] = 0; 157 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 158 | values += F(";"); 159 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 160 | values += F(";0"); 161 | values.toCharArray(str, 80); 162 | root[F("svalue")] = str; 163 | break; 164 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 165 | root[F("nvalue")] = 0; 166 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 167 | values += F(";0;0;"); 168 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 169 | values += F(";0"); 170 | values.toCharArray(str, 80); 171 | root[F("svalue")] = str; 172 | break; 173 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 174 | root[F("nvalue")] = 0; 175 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 176 | values += F(";"); 177 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 178 | values += F(";0;"); 179 | values += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 180 | values += ";0"; 181 | values.toCharArray(str, 80); 182 | root[F("svalue")] = str; 183 | break; 184 | case SENSOR_TYPE_SWITCH: 185 | root[F("command")] = String(F("switchlight")); 186 | if (UserVar[event->BaseVarIndex] == 0) 187 | root[F("switchcmd")] = F("Off"); 188 | else 189 | root[F("switchcmd")] = F("On"); 190 | break; 191 | case SENSOR_TYPE_DIMMER: 192 | root[F("command")] = String(F("switchlight")); 193 | if (UserVar[event->BaseVarIndex] == 0) 194 | root[F("switchcmd")] = String(F("Off")); 195 | else 196 | root[F("Set%20Level")] = UserVar[event->BaseVarIndex]; 197 | break; 198 | } 199 | 200 | char json[256]; 201 | root.printTo(json, sizeof(json)); 202 | String log = F("MQTT : "); 203 | log += json; 204 | addLog(LOG_LEVEL_DEBUG, json); 205 | 206 | String pubname = Settings.MQTTpublish; 207 | pubname.replace(F("%sysname%"), Settings.Name); 208 | pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName); 209 | pubname.replace(F("%id%"), String(event->idx)); 210 | 211 | if (!MQTTclient.publish(pubname.c_str(), json, Settings.MQTTRetainFlag)) 212 | { 213 | log = F("MQTT publish failed"); 214 | addLog(LOG_LEVEL_DEBUG, json); 215 | MQTTConnect(); 216 | connectionFailures++; 217 | } 218 | else if (connectionFailures) 219 | connectionFailures--; 220 | break; 221 | } 222 | 223 | } 224 | return success; 225 | } 226 | #endif 227 | 228 | -------------------------------------------------------------------------------- /src/_C005.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 005: OpenHAB MQTT ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_005 6 | #define CPLUGIN_ID_005 5 7 | #define CPLUGIN_NAME_005 "OpenHAB MQTT" 8 | 9 | boolean CPlugin_005(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_005; 18 | Protocol[protocolCount].usesMQTT = true; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_005); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTsubscribe, PSTR("/%sysname%/#")); 35 | strcpy_P(Settings.MQTTpublish, PSTR("/%sysname%/%tskname%/%valname%")); 36 | break; 37 | } 38 | 39 | case CPLUGIN_PROTOCOL_RECV: 40 | { 41 | // Split topic into array 42 | String tmpTopic = event->String1.substring(1); 43 | String topicSplit[10]; 44 | int SlashIndex = tmpTopic.indexOf('/'); 45 | byte count = 0; 46 | while (SlashIndex > 0 && count < 10 - 1) 47 | { 48 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 49 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 50 | SlashIndex = tmpTopic.indexOf('/'); 51 | count++; 52 | } 53 | topicSplit[count] = tmpTopic; 54 | 55 | String cmd = ""; 56 | struct EventStruct TempEvent; 57 | 58 | if (topicSplit[count] == F("cmd")) 59 | { 60 | cmd = event->String2; 61 | parseCommandString(&TempEvent, cmd); 62 | TempEvent.Source = VALUE_SOURCE_MQTT; 63 | } 64 | else 65 | { 66 | cmd = topicSplit[count - 1]; 67 | TempEvent.Par1 = topicSplit[count].toInt(); 68 | TempEvent.Par2 = event->String2.toFloat(); 69 | TempEvent.Par3 = 0; 70 | } 71 | // in case of event, store to buffer and return... 72 | String command = parseString(cmd, 1); 73 | if (command == F("event")) 74 | eventBuffer = cmd.substring(6); 75 | else 76 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 77 | break; 78 | } 79 | 80 | case CPLUGIN_PROTOCOL_SEND: 81 | { 82 | statusLED(true); 83 | 84 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 85 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 86 | 87 | String pubname = Settings.MQTTpublish; 88 | pubname.replace(F("%sysname%"), Settings.Name); 89 | pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName); 90 | pubname.replace(F("%id%"), String(event->idx)); 91 | 92 | String value = ""; 93 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 94 | byte valueCount = getValueCountFromSensorType(event->sensorType); 95 | for (byte x = 0; x < valueCount; x++) 96 | { 97 | String tmppubname = pubname; 98 | tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); 99 | if (event->sensorType == SENSOR_TYPE_LONG) 100 | value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 101 | else 102 | value = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 103 | MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag); 104 | } 105 | break; 106 | } 107 | return success; 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /src/_P001_Switch.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 001: Input Switch ######################################### 3 | //####################################################################################################### 4 | 5 | // Adapted from ESP Easy, changes: 6 | // WebServer.arg() -> WebServer.arg() 7 | // Changed pin limit from 0-16 to 2-13 8 | 9 | #define PLUGIN_001 10 | #define PLUGIN_ID_001 1 11 | #define PLUGIN_NAME_001 "Switch input" 12 | #define PLUGIN_VALUENAME1_001 "Switch" 13 | 14 | boolean Plugin_001(byte function, struct EventStruct *event, String& string) 15 | { 16 | boolean success = false; 17 | static byte switchstate[TASKS_MAX]; 18 | static byte outputstate[TASKS_MAX]; 19 | 20 | switch (function) 21 | { 22 | case PLUGIN_DEVICE_ADD: 23 | { 24 | Device[++deviceCount].Number = PLUGIN_ID_001; 25 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 26 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 27 | Device[deviceCount].Ports = 0; 28 | Device[deviceCount].PullUpOption = true; 29 | Device[deviceCount].InverseLogicOption = true; 30 | Device[deviceCount].FormulaOption = false; 31 | Device[deviceCount].ValueCount = 1; 32 | Device[deviceCount].SendDataOption = true; 33 | Device[deviceCount].TimerOption = true; 34 | Device[deviceCount].TimerOptional = true; 35 | Device[deviceCount].GlobalSyncOption = true; 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICENAME: 40 | { 41 | string = F(PLUGIN_NAME_001); 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICEVALUENAMES: 46 | { 47 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_001)); 48 | break; 49 | } 50 | 51 | case PLUGIN_WEBFORM_LOAD: 52 | { 53 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 54 | String options[2]; 55 | options[0] = F("Switch"); 56 | options[1] = F("Dimmer"); 57 | int optionValues[2]; 58 | optionValues[0] = 1; 59 | optionValues[1] = 2; 60 | string += F("Switch Type:"); 73 | 74 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 75 | { 76 | char tmpString[128]; 77 | sprintf_P(tmpString, PSTR("Dim value:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 78 | string += tmpString; 79 | } 80 | 81 | choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 82 | String buttonOptions[3]; 83 | buttonOptions[0] = F("Normal Switch"); 84 | buttonOptions[1] = F("Push Button Active Low"); 85 | buttonOptions[2] = F("Push Button Active High"); 86 | int buttonOptionValues[3]; 87 | buttonOptionValues[0] = 0; 88 | buttonOptionValues[1] = 1; 89 | buttonOptionValues[2] = 2; 90 | string += F("Switch Button Type:"); 103 | 104 | string += F("Send Boot state:"); 105 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][3]) 106 | string += F(""); 107 | else 108 | string += F(""); 109 | 110 | success = true; 111 | break; 112 | } 113 | 114 | case PLUGIN_WEBFORM_SAVE: 115 | { 116 | String plugin1 = WebServer.arg(F("plugin_001_type")); 117 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 118 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 119 | { 120 | String plugin2 = WebServer.arg(F("plugin_001_dimvalue")); 121 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 122 | } 123 | String plugin3 = WebServer.arg(F("plugin_001_button")); 124 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); 125 | 126 | String plugin4 = WebServer.arg(F("plugin_001_boot")); 127 | Settings.TaskDevicePluginConfig[event->TaskIndex][3] = (plugin4 == "on"); 128 | 129 | success = true; 130 | break; 131 | } 132 | 133 | case PLUGIN_INIT: 134 | { 135 | if (Settings.TaskDevicePin1PullUp[event->TaskIndex]) 136 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 137 | else 138 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT); 139 | 140 | setPinState(PLUGIN_ID_001, Settings.TaskDevicePin1[event->TaskIndex], PIN_MODE_INPUT, 0); 141 | 142 | switchstate[event->TaskIndex] = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]); 143 | outputstate[event->TaskIndex] = switchstate[event->TaskIndex]; 144 | 145 | // if boot state must be send, inverse default state 146 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][3]) 147 | { 148 | switchstate[event->TaskIndex] = !switchstate[event->TaskIndex]; 149 | outputstate[event->TaskIndex] = !outputstate[event->TaskIndex]; 150 | } 151 | success = true; 152 | break; 153 | } 154 | 155 | case PLUGIN_TEN_PER_SECOND: 156 | { 157 | byte state = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]); 158 | if (state != switchstate[event->TaskIndex]) 159 | { 160 | switchstate[event->TaskIndex] = state; 161 | byte currentOutputState = outputstate[event->TaskIndex]; 162 | 163 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) //normal switch 164 | outputstate[event->TaskIndex] = state; 165 | else 166 | { 167 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 1) // active low push button 168 | { 169 | if (state == 0) 170 | outputstate[event->TaskIndex] = !outputstate[event->TaskIndex]; 171 | } 172 | else // active high push button 173 | { 174 | if (state == 1) 175 | outputstate[event->TaskIndex] = !outputstate[event->TaskIndex]; 176 | } 177 | } 178 | 179 | // send if output needs to be changed 180 | if (currentOutputState != outputstate[event->TaskIndex]) 181 | { 182 | byte sendState = outputstate[event->TaskIndex]; 183 | if (Settings.TaskDevicePin1Inversed[event->TaskIndex]) 184 | sendState = !outputstate[event->TaskIndex]; 185 | UserVar[event->BaseVarIndex] = sendState; 186 | event->sensorType = SENSOR_TYPE_SWITCH; 187 | if ((sendState == 1) && (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)) 188 | { 189 | event->sensorType = SENSOR_TYPE_DIMMER; 190 | UserVar[event->BaseVarIndex] = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 191 | } 192 | String log = F("SW : State "); 193 | log += sendState; 194 | addLog(LOG_LEVEL_INFO, log); 195 | sendData(event); 196 | } 197 | } 198 | success = true; 199 | break; 200 | } 201 | 202 | case PLUGIN_READ: 203 | { 204 | // We do not actually read the pin state as this is already done 10x/second 205 | // Instead we just send the last known state stored in Uservar 206 | String log = F("SW : State "); 207 | log += UserVar[event->BaseVarIndex]; 208 | addLog(LOG_LEVEL_INFO, log); 209 | success = true; 210 | break; 211 | } 212 | 213 | case PLUGIN_WRITE: 214 | { 215 | String log = ""; 216 | String command = parseString(string, 1); 217 | 218 | if (command == F("gpio")) 219 | { 220 | success = true; 221 | if (event->Par1 >= 2 && event->Par1 <= 13) 222 | { 223 | pinMode(event->Par1, OUTPUT); 224 | digitalWrite(event->Par1, event->Par2); 225 | setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2); 226 | log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2); 227 | addLog(LOG_LEVEL_INFO, log); 228 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0)); 229 | } 230 | } 231 | 232 | if (command == F("pwm")) 233 | { 234 | success = true; 235 | if (event->Par1 >= 2 && event->Par1 <= 13) 236 | { 237 | pinMode(event->Par1, OUTPUT); 238 | 239 | if(event->Par3 != 0) 240 | { 241 | byte prev_mode; 242 | uint16_t prev_value; 243 | getPinState(PLUGIN_ID_001, event->Par1, &prev_mode, &prev_value); 244 | if(prev_mode != PIN_MODE_PWM) 245 | prev_value = 0; 246 | 247 | int32_t step_value = ((event->Par2 - prev_value) << 12) / event->Par3; 248 | int32_t curr_value = prev_value << 12; 249 | int16_t new_value; 250 | int i = event->Par3; 251 | while(i--){ 252 | curr_value += step_value; 253 | new_value = (uint16_t)(curr_value >> 12); 254 | analogWrite(event->Par1, new_value); 255 | delay(1); 256 | } 257 | } 258 | 259 | analogWrite(event->Par1, event->Par2); 260 | setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_PWM, event->Par2); 261 | log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); 262 | addLog(LOG_LEVEL_INFO, log); 263 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0)); 264 | } 265 | } 266 | 267 | if (command == F("pulse")) 268 | { 269 | success = true; 270 | if (event->Par1 >= 2 && event->Par1 <= 13) 271 | { 272 | pinMode(event->Par1, OUTPUT); 273 | digitalWrite(event->Par1, event->Par2); 274 | delay(event->Par3); 275 | digitalWrite(event->Par1, !event->Par2); 276 | setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2); 277 | log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS")); 278 | addLog(LOG_LEVEL_INFO, log); 279 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0)); 280 | } 281 | } 282 | 283 | if (command == F("longpulse")) 284 | { 285 | success = true; 286 | if (event->Par1 >= 2 && event->Par1 <= 13) 287 | { 288 | pinMode(event->Par1, OUTPUT); 289 | digitalWrite(event->Par1, event->Par2); 290 | setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2); 291 | setSystemTimer(event->Par3 * 1000, PLUGIN_ID_001, event->Par1, !event->Par2, 0); 292 | log = String(F("SW : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S")); 293 | addLog(LOG_LEVEL_INFO, log); 294 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par1, log, 0)); 295 | } 296 | } 297 | 298 | if (command == F("servo")) 299 | { 300 | success = true; 301 | if (event->Par1 >= 0 && event->Par1 <= 2) 302 | switch (event->Par1) 303 | { 304 | case 1: 305 | // todo myservo1.attach(event->Par2); 306 | // todo myservo1.write(event->Par3); 307 | break; 308 | case 2: 309 | // todo myservo2.attach(event->Par2); 310 | // todo myservo2.write(event->Par3); 311 | break; 312 | } 313 | setPinState(PLUGIN_ID_001, event->Par2, PIN_MODE_SERVO, event->Par3); 314 | log = String(F("SW : GPIO ")) + String(event->Par2) + String(F(" Servo set to ")) + String(event->Par3); 315 | addLog(LOG_LEVEL_INFO, log); 316 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par2, log, 0)); 317 | } 318 | 319 | if (command == F("status")) 320 | { 321 | if (parseString(string, 2) == F("gpio")) 322 | { 323 | success = true; 324 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_001, event->Par2, dummyString, 0)); 325 | } 326 | } 327 | 328 | if (command == F("inputswitchstate")) 329 | { 330 | success = true; 331 | UserVar[event->Par1 * VARS_PER_TASK] = event->Par2; 332 | outputstate[event->Par1] = event->Par2; 333 | } 334 | 335 | break; 336 | } 337 | 338 | case PLUGIN_TIMER_IN: 339 | { 340 | digitalWrite(event->Par1, event->Par2); 341 | setPinState(PLUGIN_ID_001, event->Par1, PIN_MODE_OUTPUT, event->Par2); 342 | break; 343 | } 344 | } 345 | return success; 346 | } 347 | -------------------------------------------------------------------------------- /src/_P002_ADC.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 002: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | // Adapted from ESP Easy, changes: 6 | // WebServer.arg() -> WebServer.arg() 7 | // port selection as we have a lot of analog ports here... 8 | 9 | #define PLUGIN_002 10 | #define PLUGIN_ID_002 2 11 | #define PLUGIN_NAME_002 "Analog input" 12 | #define PLUGIN_VALUENAME1_002 "Analog" 13 | boolean Plugin_002(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | Device[++deviceCount].Number = PLUGIN_ID_002; 23 | Device[deviceCount].Type = DEVICE_TYPE_ANALOG; 24 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 25 | Device[deviceCount].Ports = 1; 26 | Device[deviceCount].PullUpOption = false; 27 | Device[deviceCount].InverseLogicOption = false; 28 | Device[deviceCount].FormulaOption = true; 29 | Device[deviceCount].ValueCount = 1; 30 | Device[deviceCount].SendDataOption = true; 31 | Device[deviceCount].TimerOption = true; 32 | Device[deviceCount].GlobalSyncOption = true; 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICENAME: 37 | { 38 | string = F(PLUGIN_NAME_002); 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICEVALUENAMES: 43 | { 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002)); 45 | break; 46 | } 47 | 48 | case PLUGIN_READ: 49 | { 50 | int value = analogRead(Settings.TaskDevicePort[event->TaskIndex]); 51 | UserVar[event->BaseVarIndex] = (float)value; 52 | String log = F("ADC : Analog port "); 53 | log += Settings.TaskDevicePort[event->TaskIndex]; 54 | log += F(" value: "); 55 | log += value; 56 | addLog(LOG_LEVEL_INFO,log); 57 | success = true; 58 | break; 59 | } 60 | } 61 | return success; 62 | } 63 | -------------------------------------------------------------------------------- /src/_P003_Pulse.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 003: Pulse ############################################### 3 | //####################################################################################################### 4 | 5 | // Adapted from ESP Easy, changes: 6 | // WebServer.arg() -> WebServer.arg() 7 | 8 | #define PLUGIN_003 9 | #define PLUGIN_ID_003 3 10 | #define PLUGIN_NAME_003 "Pulse Counter" 11 | #define PLUGIN_VALUENAME1_003 "Count" 12 | #define PLUGIN_VALUENAME2_003 "Total" 13 | #define PLUGIN_VALUENAME3_003 "Time" 14 | 15 | unsigned long Plugin_003_pulseCounter[TASKS_MAX]; 16 | unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX]; 17 | unsigned long Plugin_003_pulseTime[TASKS_MAX]; 18 | unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX]; 19 | 20 | boolean Plugin_003(byte function, struct EventStruct *event, String& string) 21 | { 22 | boolean success = false; 23 | 24 | switch (function) 25 | { 26 | 27 | case PLUGIN_DEVICE_ADD: 28 | { 29 | Device[++deviceCount].Number = PLUGIN_ID_003; 30 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 31 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 32 | Device[deviceCount].Ports = 0; 33 | Device[deviceCount].PullUpOption = false; 34 | Device[deviceCount].InverseLogicOption = false; 35 | Device[deviceCount].FormulaOption = true; 36 | Device[deviceCount].ValueCount = 3; 37 | Device[deviceCount].SendDataOption = true; 38 | Device[deviceCount].TimerOption = true; 39 | Device[deviceCount].GlobalSyncOption = true; 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICENAME: 44 | { 45 | string = F(PLUGIN_NAME_003); 46 | break; 47 | } 48 | 49 | case PLUGIN_GET_DEVICEVALUENAMES: 50 | { 51 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003)); 52 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003)); 53 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_003)); 54 | break; 55 | } 56 | 57 | case PLUGIN_WEBFORM_LOAD: 58 | { 59 | char tmpString[128]; 60 | sprintf_P(tmpString, PSTR("Debounce Time (mSec):"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 61 | string += tmpString; 62 | 63 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 64 | String options[3]; 65 | options[0] = F("Delta"); 66 | options[1] = F("Delta/Total/Time"); 67 | options[2] = F("Total"); 68 | int optionValues[3]; 69 | optionValues[0] = 0; 70 | optionValues[1] = 1; 71 | optionValues[2] = 2; 72 | string += F("Counter Type:"); 85 | 86 | if (choice !=0) 87 | string += F("Total count is not persistent!"); 88 | 89 | success = true; 90 | break; 91 | } 92 | 93 | case PLUGIN_WEBFORM_SAVE: 94 | { 95 | String plugin1 = WebServer.arg(F("plugin_003")); 96 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 97 | String plugin2 = WebServer.arg(F("plugin_003_countertype")); 98 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 99 | success = true; 100 | break; 101 | } 102 | 103 | case PLUGIN_WEBFORM_SHOW_VALUES: 104 | { 105 | string += F("
"); 106 | string += ExtraTaskSettings.TaskDeviceValueNames[0]; 107 | string += F(":
"); 108 | string += Plugin_003_pulseCounter[event->TaskIndex]; 109 | string += F("
"); 110 | string += ExtraTaskSettings.TaskDeviceValueNames[1]; 111 | string += F(":
"); 112 | string += Plugin_003_pulseTotalCounter[event->TaskIndex]; 113 | string += F("
"); 114 | string += ExtraTaskSettings.TaskDeviceValueNames[2]; 115 | string += F(":
"); 116 | string += Plugin_003_pulseTime[event->TaskIndex]; 117 | string += F("
"); 118 | success = true; 119 | break; 120 | } 121 | 122 | case PLUGIN_INIT: 123 | { 124 | String log = F("INIT : Pulse "); 125 | log += Settings.TaskDevicePin1[event->TaskIndex]; 126 | addLog(LOG_LEVEL_INFO,log); 127 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 128 | Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex); 129 | success = true; 130 | break; 131 | } 132 | 133 | case PLUGIN_READ: 134 | { 135 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 136 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 137 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 138 | 139 | switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 140 | { 141 | case 0: 142 | { 143 | event->sensorType = SENSOR_TYPE_SINGLE; 144 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 145 | break; 146 | } 147 | case 1: 148 | { 149 | event->sensorType = SENSOR_TYPE_TRIPLE; 150 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 151 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 152 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 153 | break; 154 | } 155 | case 2: 156 | { 157 | event->sensorType = SENSOR_TYPE_SINGLE; 158 | UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 159 | break; 160 | } 161 | } 162 | Plugin_003_pulseCounter[event->TaskIndex] = 0; 163 | success = true; 164 | break; 165 | } 166 | } 167 | return success; 168 | } 169 | 170 | 171 | /*********************************************************************************************\ 172 | * Check Pulse Counters (called from irq handler) 173 | \*********************************************************************************************/ 174 | void Plugin_003_pulsecheck(byte Index) 175 | { 176 | unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index]; 177 | if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task 178 | { 179 | Plugin_003_pulseCounter[Index]++; 180 | Plugin_003_pulseTotalCounter[Index]++; 181 | Plugin_003_pulseTime[Index] = PulseTime; 182 | Plugin_003_pulseTimePrevious[Index]=millis(); 183 | } 184 | } 185 | 186 | 187 | /*********************************************************************************************\ 188 | * Pulse Counter IRQ handlers 189 | \*********************************************************************************************/ 190 | void Plugin_003_pulse_interrupt1() 191 | { 192 | Plugin_003_pulsecheck(0); 193 | } 194 | void Plugin_003_pulse_interrupt2() 195 | { 196 | Plugin_003_pulsecheck(1); 197 | } 198 | void Plugin_003_pulse_interrupt3() 199 | { 200 | Plugin_003_pulsecheck(2); 201 | } 202 | void Plugin_003_pulse_interrupt4() 203 | { 204 | Plugin_003_pulsecheck(3); 205 | } 206 | void Plugin_003_pulse_interrupt5() 207 | { 208 | Plugin_003_pulsecheck(4); 209 | } 210 | void Plugin_003_pulse_interrupt6() 211 | { 212 | Plugin_003_pulsecheck(5); 213 | } 214 | void Plugin_003_pulse_interrupt7() 215 | { 216 | Plugin_003_pulsecheck(6); 217 | } 218 | void Plugin_003_pulse_interrupt8() 219 | { 220 | Plugin_003_pulsecheck(7); 221 | } 222 | 223 | 224 | /*********************************************************************************************\ 225 | * Init Pulse Counters 226 | \*********************************************************************************************/ 227 | void Plugin_003_pulseinit(byte Par1, byte Index) 228 | { 229 | // Init IO pins 230 | String log = F("PULSE: Init"); 231 | addLog(LOG_LEVEL_INFO,log); 232 | 233 | switch (Index) 234 | { 235 | case 0: 236 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt1, FALLING); 237 | break; 238 | case 1: 239 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt2, FALLING); 240 | break; 241 | case 2: 242 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt3, FALLING); 243 | break; 244 | case 3: 245 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt4, FALLING); 246 | break; 247 | case 4: 248 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt5, FALLING); 249 | break; 250 | case 5: 251 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt6, FALLING); 252 | break; 253 | case 6: 254 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt7, FALLING); 255 | break; 256 | case 7: 257 | attachInterrupt(digitalPinToInterrupt(Par1), Plugin_003_pulse_interrupt8, FALLING); 258 | break; 259 | } 260 | } 261 | -------------------------------------------------------------------------------- /src/_P004_Dallas.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 004: TempSensor Dallas DS18B20 ########################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_004 6 | #define PLUGIN_ID_004 4 7 | #define PLUGIN_NAME_004 "Temperature - DS18b20" 8 | #define PLUGIN_VALUENAME1_004 "Temperature" 9 | 10 | #define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) 11 | #define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) 12 | #define IO_REG_TYPE uint8_t 13 | #define IO_REG_ASM asm("r30") 14 | #define DIRECT_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) 15 | #define DIRECT_MODE_INPUT(base, mask) ((*((base)+1)) &= ~(mask)) 16 | #define DIRECT_MODE_OUTPUT(base, mask) ((*((base)+1)) |= (mask)) 17 | #define DIRECT_WRITE_LOW(base, mask) ((*((base)+2)) &= ~(mask)) 18 | #define DIRECT_WRITE_HIGH(base, mask) ((*((base)+2)) |= (mask)) 19 | 20 | IO_REG_TYPE bitmask; 21 | volatile IO_REG_TYPE *baseReg; 22 | uint8_t Plugin_004_DallasPin; 23 | 24 | boolean Plugin_004(byte function, struct EventStruct *event, String& string) 25 | { 26 | boolean success = false; 27 | 28 | switch (function) 29 | { 30 | 31 | case PLUGIN_DEVICE_ADD: 32 | { 33 | Device[++deviceCount].Number = PLUGIN_ID_004; 34 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 35 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 36 | Device[deviceCount].Ports = 0; 37 | Device[deviceCount].PullUpOption = false; 38 | Device[deviceCount].InverseLogicOption = false; 39 | Device[deviceCount].FormulaOption = true; 40 | Device[deviceCount].ValueCount = 1; 41 | Device[deviceCount].SendDataOption = true; 42 | Device[deviceCount].TimerOption = true; 43 | Device[deviceCount].GlobalSyncOption = true; 44 | break; 45 | } 46 | 47 | case PLUGIN_GET_DEVICENAME: 48 | { 49 | string = F(PLUGIN_NAME_004); 50 | break; 51 | } 52 | 53 | case PLUGIN_GET_DEVICEVALUENAMES: 54 | { 55 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_004)); 56 | break; 57 | } 58 | 59 | case PLUGIN_WEBFORM_LOAD: 60 | { 61 | uint8_t addr[8]; 62 | 63 | // Scan the onewire bus and fill dropdown list with devicecount on this GPIO. 64 | Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex]; 65 | 66 | bitmask = PIN_TO_BITMASK(Plugin_004_DallasPin ); 67 | baseReg = PIN_TO_BASEREG(Plugin_004_DallasPin ); 68 | 69 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 70 | byte devCount = Plugin_004_DS_scan(choice, addr); 71 | string += F("Device Nr: ROM: "); 84 | if (devCount) 85 | { 86 | for (byte i = 0; i < 8; i++) 87 | { 88 | string += String(addr[i], HEX); 89 | if (i < 7) string += "-"; 90 | } 91 | } 92 | success = true; 93 | break; 94 | } 95 | 96 | case PLUGIN_WEBFORM_SAVE: 97 | { 98 | uint8_t addr[8]; 99 | String plugin1 = WebServer.arg(F("plugin_004_dev")); 100 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 101 | 102 | // find the address for selected device and store into extra tasksettings 103 | Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex]; 104 | byte devCount = Plugin_004_DS_scan(Settings.TaskDevicePluginConfig[event->TaskIndex][0], addr); 105 | for (byte x = 0; x < 8; x++) 106 | ExtraTaskSettings.TaskDevicePluginConfigLong[x] = addr[x]; 107 | success = true; 108 | break; 109 | } 110 | 111 | case PLUGIN_WEBFORM_SHOW_CONFIG: 112 | { 113 | for (byte x = 0; x < 8; x++) 114 | { 115 | if (x != 0) 116 | string += "-"; 117 | string += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX); 118 | } 119 | success = true; 120 | break; 121 | } 122 | 123 | case PLUGIN_READ: 124 | { 125 | bitmask = PIN_TO_BITMASK(Plugin_004_DallasPin ); 126 | baseReg = PIN_TO_BASEREG(Plugin_004_DallasPin ); 127 | uint8_t addr[8]; 128 | // Load ROM address from tasksettings 129 | LoadTaskSettings(event->TaskIndex); 130 | for (byte x = 0; x < 8; x++) 131 | addr[x] = ExtraTaskSettings.TaskDevicePluginConfigLong[x]; 132 | 133 | Plugin_004_DallasPin = Settings.TaskDevicePin1[event->TaskIndex]; 134 | float value = 0; 135 | String log = F("DS : Temperature: "); 136 | if (Plugin_004_DS_readTemp(addr, &value)) 137 | { 138 | UserVar[event->BaseVarIndex] = value; 139 | log += UserVar[event->BaseVarIndex]; 140 | success = true; 141 | } 142 | else 143 | { 144 | UserVar[event->BaseVarIndex] = NAN; 145 | log += F("Error!"); 146 | } 147 | log += (" ("); 148 | for (byte x = 0; x < 8; x++) 149 | { 150 | if (x != 0) 151 | log += "-"; 152 | log += String(ExtraTaskSettings.TaskDevicePluginConfigLong[x], HEX); 153 | } 154 | log += ')'; 155 | addLog(LOG_LEVEL_INFO, log); 156 | break; 157 | } 158 | 159 | } 160 | return success; 161 | } 162 | 163 | 164 | /*********************************************************************************************\ 165 | Dallas Scan bus 166 | \*********************************************************************************************/ 167 | byte Plugin_004_DS_scan(byte getDeviceROM, uint8_t* ROM) 168 | { 169 | byte tmpaddr[8]; 170 | byte devCount = 0; 171 | Plugin_004_DS_reset(); 172 | 173 | Plugin_004_DS_reset_search(); 174 | while (Plugin_004_DS_search(tmpaddr)) 175 | { 176 | if (getDeviceROM == devCount) 177 | for (byte i = 0; i < 8; i++) 178 | ROM[i] = tmpaddr[i]; 179 | devCount++; 180 | } 181 | return devCount; 182 | } 183 | 184 | 185 | /*********************************************************************************************\ 186 | Dallas Read temperature 187 | \*********************************************************************************************/ 188 | boolean Plugin_004_DS_readTemp(uint8_t ROM[8], float *value) 189 | { 190 | int16_t DSTemp; 191 | byte ScratchPad[12]; 192 | 193 | Plugin_004_DS_reset(); 194 | Plugin_004_DS_write(0x55); // Choose ROM 195 | for (byte i = 0; i < 8; i++) 196 | Plugin_004_DS_write(ROM[i]); 197 | Plugin_004_DS_write(0x44); 198 | 199 | delay(800); 200 | 201 | Plugin_004_DS_reset(); 202 | Plugin_004_DS_write(0x55); // Choose ROM 203 | for (byte i = 0; i < 8; i++) 204 | Plugin_004_DS_write(ROM[i]); 205 | Plugin_004_DS_write(0xBE); // Read scratchpad 206 | 207 | for (byte i = 0; i < 9; i++) // copy 8 bytes 208 | ScratchPad[i] = Plugin_004_DS_read(); 209 | 210 | if (Plugin_004_DS_crc8(ScratchPad, 8) != ScratchPad[8]) 211 | { 212 | *value = 0; 213 | return false; 214 | } 215 | 216 | if ((ROM[0] == 0x28 ) || (ROM[0] == 0x3b)) //DS18B20 or DS1825 217 | { 218 | DSTemp = (ScratchPad[1] << 8) + ScratchPad[0]; 219 | *value = (float(DSTemp) * 0.0625); 220 | } 221 | else if (ROM[0] == 0x10 ) //DS1820 DS18S20 222 | { 223 | DSTemp = (ScratchPad[1] << 11) | ScratchPad[0] << 3; 224 | DSTemp = ((DSTemp & 0xfff0) << 3) - 16 + 225 | ( 226 | ((ScratchPad[7] - ScratchPad[6]) << 7) / 227 | ScratchPad[7] 228 | ); 229 | *value = float(DSTemp) * 0.0078125; 230 | } 231 | return true; 232 | } 233 | 234 | 235 | /*********************************************************************************************\ 236 | Dallas Reset 237 | \*********************************************************************************************/ 238 | uint8_t Plugin_004_DS_reset() 239 | { 240 | IO_REG_TYPE mask = bitmask; 241 | volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; 242 | uint8_t r; 243 | uint8_t retries = 125; 244 | 245 | noInterrupts(); 246 | DIRECT_MODE_INPUT(reg, mask); 247 | interrupts(); 248 | // wait until the wire is high... just in case 249 | do { 250 | if (--retries == 0) return 0; 251 | delayMicroseconds(2); 252 | } while ( !DIRECT_READ(reg, mask)); 253 | 254 | noInterrupts(); 255 | DIRECT_WRITE_LOW(reg, mask); 256 | DIRECT_MODE_OUTPUT(reg, mask); // drive output low 257 | interrupts(); 258 | delayMicroseconds(480); 259 | noInterrupts(); 260 | DIRECT_MODE_INPUT(reg, mask); // allow it to float 261 | delayMicroseconds(70); 262 | r = !DIRECT_READ(reg, mask); 263 | interrupts(); 264 | delayMicroseconds(410); 265 | return r; 266 | } 267 | 268 | 269 | #define FALSE 0 270 | #define TRUE 1 271 | 272 | unsigned char ROM_NO[8]; 273 | uint8_t LastDiscrepancy; 274 | uint8_t LastFamilyDiscrepancy; 275 | uint8_t LastDeviceFlag; 276 | 277 | 278 | /*********************************************************************************************\ 279 | Dallas Reset Search 280 | \*********************************************************************************************/ 281 | void Plugin_004_DS_reset_search() 282 | { 283 | // reset the search state 284 | LastDiscrepancy = 0; 285 | LastDeviceFlag = FALSE; 286 | LastFamilyDiscrepancy = 0; 287 | for (byte i = 0; i < 8; i++) 288 | ROM_NO[i] = 0; 289 | } 290 | 291 | 292 | /*********************************************************************************************\ 293 | Dallas Search bus 294 | \*********************************************************************************************/ 295 | uint8_t Plugin_004_DS_search(uint8_t *newAddr) 296 | { 297 | uint8_t id_bit_number; 298 | uint8_t last_zero, rom_byte_number, search_result; 299 | uint8_t id_bit, cmp_id_bit; 300 | unsigned char rom_byte_mask, search_direction; 301 | 302 | // initialize for search 303 | id_bit_number = 1; 304 | last_zero = 0; 305 | rom_byte_number = 0; 306 | rom_byte_mask = 1; 307 | search_result = 0; 308 | 309 | // if the last call was not the last one 310 | if (!LastDeviceFlag) 311 | { 312 | // 1-Wire reset 313 | if (!Plugin_004_DS_reset()) 314 | { 315 | // reset the search 316 | LastDiscrepancy = 0; 317 | LastDeviceFlag = FALSE; 318 | LastFamilyDiscrepancy = 0; 319 | return FALSE; 320 | } 321 | 322 | // issue the search command 323 | Plugin_004_DS_write(0xF0); 324 | 325 | // loop to do the search 326 | do 327 | { 328 | // read a bit and its complement 329 | id_bit = Plugin_004_DS_read_bit(); 330 | cmp_id_bit = Plugin_004_DS_read_bit(); 331 | 332 | // check for no devices on 1-wire 333 | if ((id_bit == 1) && (cmp_id_bit == 1)) 334 | break; 335 | else 336 | { 337 | // all devices coupled have 0 or 1 338 | if (id_bit != cmp_id_bit) 339 | search_direction = id_bit; // bit write value for search 340 | else 341 | { 342 | // if this discrepancy if before the Last Discrepancy 343 | // on a previous next then pick the same as last time 344 | if (id_bit_number < LastDiscrepancy) 345 | search_direction = ((ROM_NO[rom_byte_number] & rom_byte_mask) > 0); 346 | else 347 | // if equal to last pick 1, if not then pick 0 348 | search_direction = (id_bit_number == LastDiscrepancy); 349 | 350 | // if 0 was picked then record its position in LastZero 351 | if (search_direction == 0) 352 | { 353 | last_zero = id_bit_number; 354 | 355 | // check for Last discrepancy in family 356 | if (last_zero < 9) 357 | LastFamilyDiscrepancy = last_zero; 358 | } 359 | } 360 | 361 | // set or clear the bit in the ROM byte rom_byte_number 362 | // with mask rom_byte_mask 363 | if (search_direction == 1) 364 | ROM_NO[rom_byte_number] |= rom_byte_mask; 365 | else 366 | ROM_NO[rom_byte_number] &= ~rom_byte_mask; 367 | 368 | // serial number search direction write bit 369 | Plugin_004_DS_write_bit(search_direction); 370 | 371 | // increment the byte counter id_bit_number 372 | // and shift the mask rom_byte_mask 373 | id_bit_number++; 374 | rom_byte_mask <<= 1; 375 | 376 | // if the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask 377 | if (rom_byte_mask == 0) 378 | { 379 | rom_byte_number++; 380 | rom_byte_mask = 1; 381 | } 382 | } 383 | } 384 | while (rom_byte_number < 8); // loop until through all ROM bytes 0-7 385 | 386 | // if the search was successful then 387 | if (!(id_bit_number < 65)) 388 | { 389 | // search successful so set LastDiscrepancy,LastDeviceFlag,search_result 390 | LastDiscrepancy = last_zero; 391 | 392 | // check for last device 393 | if (LastDiscrepancy == 0) 394 | LastDeviceFlag = TRUE; 395 | 396 | search_result = TRUE; 397 | } 398 | } 399 | 400 | // if no device found then reset counters so next 'search' will be like a first 401 | if (!search_result || !ROM_NO[0]) 402 | { 403 | LastDiscrepancy = 0; 404 | LastDeviceFlag = FALSE; 405 | LastFamilyDiscrepancy = 0; 406 | search_result = FALSE; 407 | } 408 | for (int i = 0; i < 8; i++) newAddr[i] = ROM_NO[i]; 409 | return search_result; 410 | } 411 | 412 | /*********************************************************************************************\ 413 | Dallas Read byte 414 | \*********************************************************************************************/ 415 | uint8_t Plugin_004_DS_read(void) 416 | { 417 | uint8_t bitMask; 418 | uint8_t r = 0; 419 | 420 | for (bitMask = 0x01; bitMask; bitMask <<= 1) 421 | if (Plugin_004_DS_read_bit()) 422 | r |= bitMask; 423 | 424 | return r; 425 | } 426 | 427 | 428 | /*********************************************************************************************\ 429 | Dallas Write byte 430 | \*********************************************************************************************/ 431 | void Plugin_004_DS_write(uint8_t ByteToWrite) 432 | { 433 | uint8_t bitMask; 434 | for (bitMask = 0x01; bitMask; bitMask <<= 1) 435 | Plugin_004_DS_write_bit( (bitMask & ByteToWrite) ? 1 : 0); 436 | } 437 | 438 | 439 | /*********************************************************************************************\ 440 | Dallas Read bit 441 | \*********************************************************************************************/ 442 | uint8_t Plugin_004_DS_read_bit(void) 443 | { 444 | IO_REG_TYPE mask=bitmask; 445 | volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; 446 | uint8_t r; 447 | 448 | noInterrupts(); 449 | DIRECT_MODE_OUTPUT(reg, mask); 450 | DIRECT_WRITE_LOW(reg, mask); 451 | delayMicroseconds(3); 452 | DIRECT_MODE_INPUT(reg, mask); // let pin float, pull up will raise 453 | delayMicroseconds(10); 454 | r = DIRECT_READ(reg, mask); 455 | interrupts(); 456 | delayMicroseconds(53); 457 | return r; 458 | } 459 | 460 | 461 | /*********************************************************************************************\ 462 | Dallas Write bit 463 | \*********************************************************************************************/ 464 | void Plugin_004_DS_write_bit(uint8_t v) 465 | { 466 | IO_REG_TYPE mask=bitmask; 467 | volatile IO_REG_TYPE *reg IO_REG_ASM = baseReg; 468 | 469 | if (v & 1) { 470 | noInterrupts(); 471 | DIRECT_WRITE_LOW(reg, mask); 472 | DIRECT_MODE_OUTPUT(reg, mask); // drive output low 473 | delayMicroseconds(10); 474 | DIRECT_WRITE_HIGH(reg, mask); // drive output high 475 | interrupts(); 476 | delayMicroseconds(55); 477 | } else { 478 | noInterrupts(); 479 | DIRECT_WRITE_LOW(reg, mask); 480 | DIRECT_MODE_OUTPUT(reg, mask); // drive output low 481 | delayMicroseconds(65); 482 | DIRECT_WRITE_HIGH(reg, mask); // drive output high 483 | interrupts(); 484 | delayMicroseconds(5); 485 | } 486 | } 487 | 488 | uint8_t Plugin_004_DS_crc8( uint8_t *addr, uint8_t len) 489 | { 490 | uint8_t crc = 0; 491 | 492 | while (len--) { 493 | uint8_t inbyte = *addr++; 494 | for (uint8_t i = 8; i; i--) { 495 | uint8_t mix = (crc ^ inbyte) & 0x01; 496 | crc >>= 1; 497 | if (mix) crc ^= 0x8C; 498 | inbyte >>= 1; 499 | } 500 | } 501 | return crc; 502 | } 503 | -------------------------------------------------------------------------------- /src/_P005_DHT.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 005: Temperature and Humidity sensor DHT 11/22 ######################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_005 6 | #define PLUGIN_ID_005 5 7 | #define PLUGIN_NAME_005 "Temperature & Humidity - DHT" 8 | #define PLUGIN_VALUENAME1_005 "Temperature" 9 | #define PLUGIN_VALUENAME2_005 "Humidity" 10 | 11 | uint8_t Plugin_005_DHT_Pin; 12 | 13 | boolean Plugin_005(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_005; 22 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 23 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 24 | Device[deviceCount].Ports = 0; 25 | Device[deviceCount].PullUpOption = false; 26 | Device[deviceCount].InverseLogicOption = false; 27 | Device[deviceCount].FormulaOption = true; 28 | Device[deviceCount].ValueCount = 2; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_005); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_005)); 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_005)); 45 | break; 46 | } 47 | 48 | case PLUGIN_WEBFORM_LOAD: 49 | { 50 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 51 | String options[3]; 52 | options[0] = F("DHT 11"); 53 | options[1] = F("DHT 22"); 54 | options[2] = F("DHT 12"); 55 | int optionValues[3]; 56 | optionValues[0] = 11; 57 | optionValues[1] = 22; 58 | optionValues[2] = 12; 59 | string += F("DHT Type:"); 72 | 73 | success = true; 74 | break; 75 | } 76 | 77 | case PLUGIN_WEBFORM_SAVE: 78 | { 79 | String plugin1 = WebServer.arg(F("plugin_005_dhttype")); 80 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_READ: 86 | { 87 | byte dht_dat[5]; 88 | byte dht_in; 89 | byte i; 90 | byte Retry = 0; 91 | boolean error = false; 92 | 93 | byte Par3 = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 94 | Plugin_005_DHT_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 95 | 96 | pinMode(Plugin_005_DHT_Pin, OUTPUT); 97 | // DHT start condition, pull-down i/o pin for 18ms 98 | digitalWrite(Plugin_005_DHT_Pin, LOW); // Pull low 99 | delay(18); 100 | digitalWrite(Plugin_005_DHT_Pin, HIGH); // Pull high 101 | delayMicroseconds(20); // was 40 102 | pinMode(Plugin_005_DHT_Pin, INPUT); // change pin to input 103 | delayMicroseconds(10); 104 | 105 | dht_in = digitalRead(Plugin_005_DHT_Pin); 106 | if (!dht_in) 107 | { 108 | delayMicroseconds(80); 109 | dht_in = digitalRead(Plugin_005_DHT_Pin); 110 | if (dht_in) 111 | { 112 | delayMicroseconds(80); // now ready for data reception 113 | for (i = 0; i < 5; i++) 114 | { 115 | byte data = Plugin_005_read_dht_dat(); 116 | if (data != -1) 117 | dht_dat[i] = data; 118 | else 119 | { 120 | String log = F("DHT : protocol timeout!"); 121 | addLog(LOG_LEVEL_ERROR, log); 122 | error = true; 123 | } 124 | } 125 | 126 | if (!error) 127 | { 128 | 129 | // Checksum calculation is a Rollover Checksum by design! 130 | byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum 131 | 132 | if (dht_dat[4] == dht_check_sum) 133 | { 134 | float temperature = NAN; 135 | float humidity = NAN; 136 | 137 | if (Par3 == 11) 138 | { 139 | temperature = float(dht_dat[2]); // Temperature 140 | humidity = float(dht_dat[0]); // Humidity 141 | } 142 | else if (Par3 == 12) 143 | { 144 | temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature 145 | if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature 146 | humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity 147 | } 148 | 149 | if (Par3 == 22) 150 | { 151 | if (dht_dat[2] & 0x80) // negative temperature 152 | temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]); 153 | else 154 | temperature = 0.1 * word(dht_dat[2], dht_dat[3]); 155 | humidity = word(dht_dat[0], dht_dat[1]) * 0.1; // Humidity 156 | } 157 | if (temperature != NAN || humidity != NAN) // According to negated original if, maybe use && instead? 158 | { 159 | UserVar[event->BaseVarIndex] = temperature; 160 | UserVar[event->BaseVarIndex + 1] = humidity; 161 | String log = F("DHT : Temperature: "); 162 | log += UserVar[event->BaseVarIndex]; 163 | addLog(LOG_LEVEL_INFO, log); 164 | log = F("DHT : Humidity: "); 165 | log += UserVar[event->BaseVarIndex + 1]; 166 | addLog(LOG_LEVEL_INFO, log); 167 | success = true; 168 | } 169 | } // checksum 170 | } // error 171 | } // dht 172 | } // !dht 173 | if(!success) 174 | { 175 | String log = F("DHT : No reading!"); 176 | addLog(LOG_LEVEL_ERROR, log); 177 | UserVar[event->BaseVarIndex] = NAN; 178 | UserVar[event->BaseVarIndex + 1] = NAN; 179 | } 180 | break; 181 | } 182 | } 183 | return success; 184 | } 185 | 186 | 187 | /*********************************************************************************************\ 188 | * DHT sub to get an 8 bit value from the receiving bitstream 189 | \*********************************************************************************************/ 190 | int Plugin_005_read_dht_dat(void) 191 | { 192 | byte i = 0; 193 | byte result = 0; 194 | byte counter = 0; 195 | //noInterrupts(); 196 | for (i = 0; i < 8; i++) 197 | { 198 | while ((!digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 199 | { 200 | delayMicroseconds(1); 201 | counter++; 202 | } 203 | if (counter >= 100) 204 | { 205 | //interrupts(); 206 | return -1; 207 | } 208 | delayMicroseconds(30); 209 | if (digitalRead(Plugin_005_DHT_Pin)) 210 | result |= (1 << (7 - i)); 211 | counter = 0; 212 | while ((digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 213 | { 214 | delayMicroseconds(1); 215 | counter++; 216 | } 217 | if (counter >= 100) 218 | { 219 | //interrupts(); 220 | return -1; 221 | } 222 | } 223 | //interrupts(); 224 | return result; 225 | } 226 | 227 | -------------------------------------------------------------------------------- /src/_P033_Dummy.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 033: Dummy ################################################ 3 | //####################################################################################################### 4 | 5 | // Adapted from ESP Easy, changes: 6 | // WebServer.arg() -> WebServer.arg() 7 | 8 | #define PLUGIN_033 9 | #define PLUGIN_ID_033 33 10 | #define PLUGIN_NAME_033 "Dummy Device" 11 | #define PLUGIN_VALUENAME1_033 "Dummy" 12 | 13 | boolean Plugin_033(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | Device[++deviceCount].Number = PLUGIN_ID_033; 23 | Device[deviceCount].Type = DEVICE_TYPE_DUMMY; 24 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 25 | Device[deviceCount].Ports = 0; 26 | Device[deviceCount].PullUpOption = false; 27 | Device[deviceCount].InverseLogicOption = false; 28 | Device[deviceCount].FormulaOption = false; 29 | Device[deviceCount].DecimalsOnly = true; 30 | Device[deviceCount].ValueCount = 4; 31 | Device[deviceCount].SendDataOption = true; 32 | Device[deviceCount].TimerOption = true; 33 | Device[deviceCount].GlobalSyncOption = true; 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICENAME: 38 | { 39 | string = F(PLUGIN_NAME_033); 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICEVALUENAMES: 44 | { 45 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_033)); 46 | break; 47 | } 48 | 49 | case PLUGIN_WEBFORM_LOAD: 50 | { 51 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 52 | String options[9]; 53 | options[0] = F("SENSOR_TYPE_SINGLE"); 54 | options[1] = F("SENSOR_TYPE_TEMP_HUM"); 55 | options[2] = F("SENSOR_TYPE_TEMP_BARO"); 56 | options[3] = F("SENSOR_TYPE_TEMP_HUM_BARO"); 57 | options[4] = F("SENSOR_TYPE_DUAL"); 58 | options[5] = F("SENSOR_TYPE_TRIPLE"); 59 | options[6] = F("SENSOR_TYPE_QUAD"); 60 | options[7] = F("SENSOR_TYPE_SWITCH"); 61 | options[8] = F("SENSOR_TYPE_DIMMER"); 62 | int optionValues[9]; 63 | optionValues[0] = SENSOR_TYPE_SINGLE; 64 | optionValues[1] = SENSOR_TYPE_TEMP_HUM; 65 | optionValues[2] = SENSOR_TYPE_TEMP_BARO; 66 | optionValues[3] = SENSOR_TYPE_TEMP_HUM_BARO; 67 | optionValues[4] = SENSOR_TYPE_DUAL; 68 | optionValues[5] = SENSOR_TYPE_TRIPLE; 69 | optionValues[6] = SENSOR_TYPE_QUAD; 70 | optionValues[7] = SENSOR_TYPE_SWITCH; 71 | optionValues[8] = SENSOR_TYPE_DIMMER; 72 | string += F("Simulate Data Type:"); 85 | 86 | success = true; 87 | break; 88 | } 89 | 90 | case PLUGIN_WEBFORM_SAVE: 91 | { 92 | String plugin1 = WebServer.arg(F("plugin_033_sensortype")); 93 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 94 | success = true; 95 | break; 96 | } 97 | 98 | case PLUGIN_READ: 99 | { 100 | event->sensorType =Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 101 | for (byte x=0; x<4;x++) 102 | { 103 | String log = F("Dummy: value "); 104 | log += x+1; 105 | log += F(": "); 106 | log += UserVar[event->BaseVarIndex+x]; 107 | addLog(LOG_LEVEL_INFO,log); 108 | } 109 | success = true; 110 | break; 111 | } 112 | } 113 | return success; 114 | } 115 | 116 | -------------------------------------------------------------------------------- /src/_P034_DHT12.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 034: Temperature and Humidity sensor DHT 12 (I2C) ##################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_034 6 | #define PLUGIN_ID_034 34 7 | #define PLUGIN_NAME_034 "Temperature & Humidity - DHT12 (I2C)" 8 | #define PLUGIN_VALUENAME1_034 "Temperature" 9 | #define PLUGIN_VALUENAME2_034 "Humidity" 10 | 11 | boolean Plugin_034_init = false; 12 | 13 | #define DHT12_I2C_ADDRESS 0x5C // I2C address for the sensor 14 | 15 | boolean Plugin_034(byte function, struct EventStruct *event, String& string) 16 | { 17 | boolean success = false; 18 | 19 | switch (function) 20 | { 21 | case PLUGIN_DEVICE_ADD: 22 | { 23 | Device[++deviceCount].Number = PLUGIN_ID_034; 24 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 25 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 26 | Device[deviceCount].Ports = 0; 27 | Device[deviceCount].PullUpOption = false; 28 | Device[deviceCount].InverseLogicOption = false; 29 | Device[deviceCount].FormulaOption = true; 30 | Device[deviceCount].ValueCount = 2; 31 | Device[deviceCount].SendDataOption = true; 32 | Device[deviceCount].TimerOption = true; 33 | Device[deviceCount].GlobalSyncOption = true; 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICENAME: 38 | { 39 | string = F(PLUGIN_NAME_034); 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICEVALUENAMES: 44 | { 45 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_034)); 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_034)); 47 | break; 48 | } 49 | 50 | case PLUGIN_READ: 51 | { 52 | byte dht_dat[5]; 53 | byte dht_in; 54 | byte i; 55 | byte Retry = 0; 56 | boolean error = false; 57 | 58 | Wire.beginTransmission(DHT12_I2C_ADDRESS); // start transmission to device 59 | Wire.write(0); // sends register address to read from 60 | Wire.endTransmission(); // end transmission 61 | 62 | Wire.beginTransmission(DHT12_I2C_ADDRESS); // start transmission to device 63 | if (Wire.requestFrom(DHT12_I2C_ADDRESS, 5) == 5) { // send data n-bytes read 64 | for (i = 0; i < 5; i++) 65 | { 66 | dht_dat[i] = Wire.read(); // receive DATA 67 | } 68 | } else { 69 | error = true; 70 | } 71 | if (!error) 72 | { 73 | // Checksum calculation is a Rollover Checksum by design! 74 | byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum 75 | 76 | if (dht_dat[4] == dht_check_sum) 77 | { 78 | float temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature 79 | if (dht_dat[3] & 0x80) { temperature = -temperature; } 80 | float humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity 81 | 82 | UserVar[event->BaseVarIndex] = temperature; 83 | UserVar[event->BaseVarIndex + 1] = humidity; 84 | String log = F("DHT12: Temperature: "); 85 | log += UserVar[event->BaseVarIndex]; 86 | addLog(LOG_LEVEL_INFO, log); 87 | log = F("DHT12: Humidity: "); 88 | log += UserVar[event->BaseVarIndex + 1]; 89 | addLog(LOG_LEVEL_INFO, log); 90 | success = true; 91 | } // checksum 92 | } // error 93 | if(!success) 94 | { 95 | String log = F("DHT12: No reading!"); 96 | addLog(LOG_LEVEL_INFO, log); 97 | UserVar[event->BaseVarIndex] = NAN; 98 | UserVar[event->BaseVarIndex + 1] = NAN; 99 | } 100 | break; 101 | } 102 | } 103 | return success; 104 | } 105 | -------------------------------------------------------------------------------- /src/__CPlugin.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Initialize all Controller CPlugins that where defined earlier 3 | // and initialize the function call pointer into the CCPlugin array 4 | //******************************************************************************** 5 | void CPluginInit(void) 6 | { 7 | byte x; 8 | 9 | // Clear pointer table for all plugins 10 | for (x = 0; x < CPLUGIN_MAX; x++) 11 | { 12 | CPlugin_ptr[x] = 0; 13 | CPlugin_id[x] = 0; 14 | } 15 | 16 | x = 0; 17 | 18 | #ifdef CPLUGIN_001 19 | CPlugin_id[x] = 1; CPlugin_ptr[x++] = &CPlugin_001; 20 | #endif 21 | 22 | #ifdef CPLUGIN_002 23 | CPlugin_id[x] = 2; CPlugin_ptr[x++] = &CPlugin_002; 24 | #endif 25 | 26 | #ifdef CPLUGIN_003 27 | CPlugin_id[x] = 3; CPlugin_ptr[x++] = &CPlugin_003; 28 | #endif 29 | 30 | #ifdef CPLUGIN_004 31 | CPlugin_id[x] = 4; CPlugin_ptr[x++] = &CPlugin_004; 32 | #endif 33 | 34 | #ifdef CPLUGIN_005 35 | CPlugin_id[x] = 5; CPlugin_ptr[x++] = &CPlugin_005; 36 | #endif 37 | 38 | #ifdef CPLUGIN_006 39 | CPlugin_id[x] = 6; CPlugin_ptr[x++] = &CPlugin_006; 40 | #endif 41 | 42 | #ifdef CPLUGIN_007 43 | CPlugin_id[x] = 7; CPlugin_ptr[x++] = &CPlugin_007; 44 | #endif 45 | 46 | #ifdef CPLUGIN_008 47 | CPlugin_id[x] = 8; CPlugin_ptr[x++] = &CPlugin_008; 48 | #endif 49 | 50 | #ifdef CPLUGIN_009 51 | CPlugin_id[x] = 9; CPlugin_ptr[x++] = &CPlugin_009; 52 | #endif 53 | 54 | #ifdef CPLUGIN_010 55 | CPlugin_id[x] = 10; CPlugin_ptr[x++] = &CPlugin_010; 56 | #endif 57 | 58 | #ifdef CPLUGIN_011 59 | CPlugin_id[x] = 11; CPlugin_ptr[x++] = &CPlugin_011; 60 | #endif 61 | 62 | #ifdef CPLUGIN_012 63 | CPlugin_id[x] = 12; CPlugin_ptr[x++] = &CPlugin_012; 64 | #endif 65 | 66 | #ifdef CPLUGIN_013 67 | CPlugin_id[x] = 13; CPlugin_ptr[x++] = &CPlugin_013; 68 | #endif 69 | 70 | #ifdef CPLUGIN_014 71 | CPlugin_id[x] = 14; CPlugin_ptr[x++] = &CPlugin_014; 72 | #endif 73 | 74 | #ifdef CPLUGIN_015 75 | CPlugin_id[x] = 15; CPlugin_ptr[x++] = &CPlugin_015; 76 | #endif 77 | 78 | #ifdef CPLUGIN_016 79 | CPlugin_id[x] = 16; CPlugin_ptr[x++] = &CPlugin_016; 80 | #endif 81 | 82 | #ifdef CPLUGIN_017 83 | CPlugin_id[x] = 17; CPlugin_ptr[x++] = &CPlugin_017; 84 | #endif 85 | 86 | #ifdef CPLUGIN_018 87 | CPlugin_id[x] = 18; CPlugin_ptr[x++] = &CPlugin_018; 88 | #endif 89 | 90 | #ifdef CPLUGIN_019 91 | CPlugin_id[x] = 19; CPlugin_ptr[x++] = &CPlugin_019; 92 | #endif 93 | 94 | #ifdef CPLUGIN_020 95 | CPlugin_id[x] = 20; CPlugin_ptr[x++] = &CPlugin_020; 96 | #endif 97 | 98 | #ifdef CPLUGIN_021 99 | CPlugin_id[x] = 21; CPlugin_ptr[x++] = &CPlugin_021; 100 | #endif 101 | 102 | #ifdef CPLUGIN_022 103 | CPlugin_id[x] = 22; CPlugin_ptr[x++] = &CPlugin_022; 104 | #endif 105 | 106 | #ifdef CPLUGIN_023 107 | CPlugin_id[x] = 23; CPlugin_ptr[x++] = &CPlugin_023; 108 | #endif 109 | 110 | #ifdef CPLUGIN_024 111 | CPlugin_id[x] = 24; CPlugin_ptr[x++] = &CPlugin_024; 112 | #endif 113 | 114 | #ifdef CPLUGIN_025 115 | CPlugin_id[x] = 25; CPlugin_ptr[x++] = &CPlugin_025; 116 | #endif 117 | 118 | CPluginCall(CPLUGIN_PROTOCOL_ADD, 0); 119 | } 120 | 121 | byte CPluginCall(byte Function, struct EventStruct *event) 122 | { 123 | int x; 124 | struct EventStruct TempEvent; 125 | 126 | if (event == 0) 127 | event=&TempEvent; 128 | 129 | switch (Function) 130 | { 131 | // Unconditional calls to all plugins 132 | case CPLUGIN_PROTOCOL_ADD: 133 | for (x = 0; x < CPLUGIN_MAX; x++) 134 | if (CPlugin_id[x] != 0) 135 | CPlugin_ptr[x](Function, event, dummyString); 136 | return true; 137 | break; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /src/__Plugin.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Initialize all plugins that where defined earlier 3 | // and initialize the function call pointer into the plugin array 4 | //******************************************************************************** 5 | void PluginInit(void) 6 | { 7 | byte x; 8 | 9 | // Clear pointer table for all plugins 10 | for (x = 0; x < PLUGIN_MAX; x++) 11 | { 12 | Plugin_ptr[x] = 0; 13 | Plugin_id[x] = 0; 14 | } 15 | 16 | x = 0; 17 | 18 | #ifdef PLUGIN_001 19 | Plugin_id[x] = 1; Plugin_ptr[x++] = &Plugin_001; 20 | #endif 21 | 22 | #ifdef PLUGIN_002 23 | Plugin_id[x] = 2; Plugin_ptr[x++] = &Plugin_002; 24 | #endif 25 | 26 | #ifdef PLUGIN_003 27 | Plugin_id[x] = 3; Plugin_ptr[x++] = &Plugin_003; 28 | #endif 29 | 30 | #ifdef PLUGIN_004 31 | Plugin_id[x] = 4; Plugin_ptr[x++] = &Plugin_004; 32 | #endif 33 | 34 | #ifdef PLUGIN_005 35 | Plugin_id[x] = 5; Plugin_ptr[x++] = &Plugin_005; 36 | #endif 37 | 38 | #ifdef PLUGIN_006 39 | Plugin_id[x] = 6; Plugin_ptr[x++] = &Plugin_006; 40 | #endif 41 | 42 | #ifdef PLUGIN_007 43 | Plugin_id[x] = 7; Plugin_ptr[x++] = &Plugin_007; 44 | #endif 45 | 46 | #ifdef PLUGIN_008 47 | Plugin_id[x] = 8; Plugin_ptr[x++] = &Plugin_008; 48 | #endif 49 | 50 | #ifdef PLUGIN_009 51 | Plugin_id[x] = 9; Plugin_ptr[x++] = &Plugin_009; 52 | #endif 53 | 54 | #ifdef PLUGIN_010 55 | Plugin_id[x] = 10; Plugin_ptr[x++] = &Plugin_010; 56 | #endif 57 | 58 | #ifdef PLUGIN_011 59 | Plugin_id[x] = 11; Plugin_ptr[x++] = &Plugin_011; 60 | #endif 61 | 62 | #ifdef PLUGIN_012 63 | Plugin_id[x] = 12; Plugin_ptr[x++] = &Plugin_012; 64 | #endif 65 | 66 | #ifdef PLUGIN_013 67 | Plugin_id[x] = 13; Plugin_ptr[x++] = &Plugin_013; 68 | #endif 69 | 70 | #ifdef PLUGIN_014 71 | Plugin_id[x] = 14; Plugin_ptr[x++] = &Plugin_014; 72 | #endif 73 | 74 | #ifdef PLUGIN_015 75 | Plugin_id[x] = 15; Plugin_ptr[x++] = &Plugin_015; 76 | #endif 77 | 78 | #ifdef PLUGIN_016 79 | Plugin_id[x] = 16; Plugin_ptr[x++] = &Plugin_016; 80 | #endif 81 | 82 | #ifdef PLUGIN_017 83 | Plugin_id[x] = 17; Plugin_ptr[x++] = &Plugin_017; 84 | #endif 85 | 86 | #ifdef PLUGIN_018 87 | Plugin_id[x] = 18; Plugin_ptr[x++] = &Plugin_018; 88 | #endif 89 | 90 | #ifdef PLUGIN_019 91 | Plugin_id[x] = 19; Plugin_ptr[x++] = &Plugin_019; 92 | #endif 93 | 94 | #ifdef PLUGIN_020 95 | Plugin_id[x] = 20; Plugin_ptr[x++] = &Plugin_020; 96 | #endif 97 | 98 | #ifdef PLUGIN_021 99 | Plugin_id[x] = 21; Plugin_ptr[x++] = &Plugin_021; 100 | #endif 101 | 102 | #ifdef PLUGIN_022 103 | Plugin_id[x] = 22; Plugin_ptr[x++] = &Plugin_022; 104 | #endif 105 | 106 | #ifdef PLUGIN_023 107 | Plugin_id[x] = 23; Plugin_ptr[x++] = &Plugin_023; 108 | #endif 109 | 110 | #ifdef PLUGIN_024 111 | Plugin_id[x] = 24; Plugin_ptr[x++] = &Plugin_024; 112 | #endif 113 | 114 | #ifdef PLUGIN_025 115 | Plugin_id[x] = 25; Plugin_ptr[x++] = &Plugin_025; 116 | #endif 117 | 118 | #ifdef PLUGIN_026 119 | Plugin_id[x] = 26; Plugin_ptr[x++] = &Plugin_026; 120 | #endif 121 | 122 | #ifdef PLUGIN_027 123 | Plugin_id[x] = 27; Plugin_ptr[x++] = &Plugin_027; 124 | #endif 125 | 126 | #ifdef PLUGIN_028 127 | Plugin_id[x] = 28; Plugin_ptr[x++] = &Plugin_028; 128 | #endif 129 | 130 | #ifdef PLUGIN_029 131 | Plugin_id[x] = 29; Plugin_ptr[x++] = &Plugin_029; 132 | #endif 133 | 134 | #ifdef PLUGIN_030 135 | Plugin_id[x] = 30; Plugin_ptr[x++] = &Plugin_030; 136 | #endif 137 | 138 | #ifdef PLUGIN_031 139 | Plugin_id[x] = 31; Plugin_ptr[x++] = &Plugin_031; 140 | #endif 141 | 142 | #ifdef PLUGIN_032 143 | Plugin_id[x] = 32; Plugin_ptr[x++] = &Plugin_032; 144 | #endif 145 | 146 | #ifdef PLUGIN_033 147 | Plugin_id[x] = 33; Plugin_ptr[x++] = &Plugin_033; 148 | #endif 149 | 150 | #ifdef PLUGIN_034 151 | Plugin_id[x] = 34; Plugin_ptr[x++] = &Plugin_034; 152 | #endif 153 | 154 | #ifdef PLUGIN_035 155 | Plugin_id[x] = 35; Plugin_ptr[x++] = &Plugin_035; 156 | #endif 157 | 158 | #ifdef PLUGIN_036 159 | Plugin_id[x] = 36; Plugin_ptr[x++] = &Plugin_036; 160 | #endif 161 | 162 | #ifdef PLUGIN_037 163 | Plugin_id[x] = 37; Plugin_ptr[x++] = &Plugin_037; 164 | #endif 165 | 166 | #ifdef PLUGIN_038 167 | Plugin_id[x] = 38; Plugin_ptr[x++] = &Plugin_038; 168 | #endif 169 | 170 | #ifdef PLUGIN_039 171 | Plugin_id[x] = 39; Plugin_ptr[x++] = &Plugin_039; 172 | #endif 173 | 174 | #ifdef PLUGIN_040 175 | Plugin_id[x] = 40; Plugin_ptr[x++] = &Plugin_040; 176 | #endif 177 | 178 | #ifdef PLUGIN_041 179 | Plugin_id[x] = 41; Plugin_ptr[x++] = &Plugin_041; 180 | #endif 181 | 182 | #ifdef PLUGIN_042 183 | Plugin_id[x] = 42; Plugin_ptr[x++] = &Plugin_042; 184 | #endif 185 | 186 | #ifdef PLUGIN_043 187 | Plugin_id[x] = 43; Plugin_ptr[x++] = &Plugin_043; 188 | #endif 189 | 190 | #ifdef PLUGIN_044 191 | Plugin_id[x] = 44; Plugin_ptr[x++] = &Plugin_044; 192 | #endif 193 | 194 | #ifdef PLUGIN_045 195 | Plugin_id[x] = 45; Plugin_ptr[x++] = &Plugin_045; 196 | #endif 197 | 198 | #ifdef PLUGIN_046 199 | Plugin_id[x] = 46; Plugin_ptr[x++] = &Plugin_046; 200 | #endif 201 | 202 | #ifdef PLUGIN_047 203 | Plugin_id[x] = 47; Plugin_ptr[x++] = &Plugin_047; 204 | #endif 205 | 206 | #ifdef PLUGIN_048 207 | Plugin_id[x] = 48; Plugin_ptr[x++] = &Plugin_048; 208 | #endif 209 | 210 | #ifdef PLUGIN_049 211 | Plugin_id[x] = 49; Plugin_ptr[x++] = &Plugin_049; 212 | #endif 213 | 214 | #ifdef PLUGIN_050 215 | Plugin_id[x] = 50; Plugin_ptr[x++] = &Plugin_050; 216 | #endif 217 | 218 | #ifdef PLUGIN_051 219 | Plugin_id[x] = 51; Plugin_ptr[x++] = &Plugin_051; 220 | #endif 221 | 222 | #ifdef PLUGIN_052 223 | Plugin_id[x] = 52; Plugin_ptr[x++] = &Plugin_052; 224 | #endif 225 | 226 | #ifdef PLUGIN_053 227 | Plugin_id[x] = 53; Plugin_ptr[x++] = &Plugin_053; 228 | #endif 229 | 230 | #ifdef PLUGIN_054 231 | Plugin_id[x] = 54; Plugin_ptr[x++] = &Plugin_054; 232 | #endif 233 | 234 | #ifdef PLUGIN_055 235 | Plugin_id[x] = 55; Plugin_ptr[x++] = &Plugin_055; 236 | #endif 237 | 238 | #ifdef PLUGIN_056 239 | Plugin_id[x] = 56; Plugin_ptr[x++] = &Plugin_056; 240 | #endif 241 | 242 | #ifdef PLUGIN_057 243 | Plugin_id[x] = 57; Plugin_ptr[x++] = &Plugin_057; 244 | #endif 245 | 246 | #ifdef PLUGIN_058 247 | Plugin_id[x] = 58; Plugin_ptr[x++] = &Plugin_058; 248 | #endif 249 | 250 | #ifdef PLUGIN_059 251 | Plugin_id[x] = 59; Plugin_ptr[x++] = &Plugin_059; 252 | #endif 253 | 254 | #ifdef PLUGIN_060 255 | Plugin_id[x] = 60; Plugin_ptr[x++] = &Plugin_060; 256 | #endif 257 | 258 | #ifdef PLUGIN_061 259 | Plugin_id[x] = 61; Plugin_ptr[x++] = &Plugin_061; 260 | #endif 261 | 262 | #ifdef PLUGIN_062 263 | Plugin_id[x] = 62; Plugin_ptr[x++] = &Plugin_062; 264 | #endif 265 | 266 | #ifdef PLUGIN_063 267 | Plugin_id[x] = 63; Plugin_ptr[x++] = &Plugin_063; 268 | #endif 269 | 270 | #ifdef PLUGIN_064 271 | Plugin_id[x] = 64; Plugin_ptr[x++] = &Plugin_064; 272 | #endif 273 | 274 | #ifdef PLUGIN_065 275 | Plugin_id[x] = 65; Plugin_ptr[x++] = &Plugin_065; 276 | #endif 277 | 278 | #ifdef PLUGIN_066 279 | Plugin_id[x] = 66; Plugin_ptr[x++] = &Plugin_066; 280 | #endif 281 | 282 | #ifdef PLUGIN_067 283 | Plugin_id[x] = 67; Plugin_ptr[x++] = &Plugin_067; 284 | #endif 285 | 286 | #ifdef PLUGIN_068 287 | Plugin_id[x] = 68; Plugin_ptr[x++] = &Plugin_068; 288 | #endif 289 | 290 | #ifdef PLUGIN_069 291 | Plugin_id[x] = 69; Plugin_ptr[x++] = &Plugin_069; 292 | #endif 293 | 294 | #ifdef PLUGIN_070 295 | Plugin_id[x] = 70; Plugin_ptr[x++] = &Plugin_070; 296 | #endif 297 | 298 | #ifdef PLUGIN_071 299 | Plugin_id[x] = 71; Plugin_ptr[x++] = &Plugin_071; 300 | #endif 301 | 302 | #ifdef PLUGIN_072 303 | Plugin_id[x] = 72; Plugin_ptr[x++] = &Plugin_072; 304 | #endif 305 | 306 | #ifdef PLUGIN_073 307 | Plugin_id[x] = 73; Plugin_ptr[x++] = &Plugin_073; 308 | #endif 309 | 310 | #ifdef PLUGIN_074 311 | Plugin_id[x] = 74; Plugin_ptr[x++] = &Plugin_074; 312 | #endif 313 | 314 | #ifdef PLUGIN_075 315 | Plugin_id[x] = 75; Plugin_ptr[x++] = &Plugin_075; 316 | #endif 317 | 318 | #ifdef PLUGIN_076 319 | Plugin_id[x] = 76; Plugin_ptr[x++] = &Plugin_076; 320 | #endif 321 | 322 | #ifdef PLUGIN_077 323 | Plugin_id[x] = 77; Plugin_ptr[x++] = &Plugin_077; 324 | #endif 325 | 326 | #ifdef PLUGIN_078 327 | Plugin_id[x] = 78; Plugin_ptr[x++] = &Plugin_078; 328 | #endif 329 | 330 | #ifdef PLUGIN_079 331 | Plugin_id[x] = 79; Plugin_ptr[x++] = &Plugin_079; 332 | #endif 333 | 334 | #ifdef PLUGIN_080 335 | Plugin_id[x] = 80; Plugin_ptr[x++] = &Plugin_080; 336 | #endif 337 | 338 | #ifdef PLUGIN_081 339 | Plugin_id[x] = 81; Plugin_ptr[x++] = &Plugin_081; 340 | #endif 341 | 342 | #ifdef PLUGIN_082 343 | Plugin_id[x] = 82; Plugin_ptr[x++] = &Plugin_082; 344 | #endif 345 | 346 | #ifdef PLUGIN_083 347 | Plugin_id[x] = 83; Plugin_ptr[x++] = &Plugin_083; 348 | #endif 349 | 350 | #ifdef PLUGIN_084 351 | Plugin_id[x] = 84; Plugin_ptr[x++] = &Plugin_084; 352 | #endif 353 | 354 | #ifdef PLUGIN_085 355 | Plugin_id[x] = 85; Plugin_ptr[x++] = &Plugin_085; 356 | #endif 357 | 358 | #ifdef PLUGIN_086 359 | Plugin_id[x] = 86; Plugin_ptr[x++] = &Plugin_086; 360 | #endif 361 | 362 | #ifdef PLUGIN_087 363 | Plugin_id[x] = 87; Plugin_ptr[x++] = &Plugin_087; 364 | #endif 365 | 366 | #ifdef PLUGIN_088 367 | Plugin_id[x] = 88; Plugin_ptr[x++] = &Plugin_088; 368 | #endif 369 | 370 | #ifdef PLUGIN_089 371 | Plugin_id[x] = 89; Plugin_ptr[x++] = &Plugin_089; 372 | #endif 373 | 374 | #ifdef PLUGIN_090 375 | Plugin_id[x] = 90; Plugin_ptr[x++] = &Plugin_090; 376 | #endif 377 | 378 | #ifdef PLUGIN_091 379 | Plugin_id[x] = 91; Plugin_ptr[x++] = &Plugin_091; 380 | #endif 381 | 382 | #ifdef PLUGIN_092 383 | Plugin_id[x] = 92; Plugin_ptr[x++] = &Plugin_092; 384 | #endif 385 | 386 | #ifdef PLUGIN_093 387 | Plugin_id[x] = 93; Plugin_ptr[x++] = &Plugin_093; 388 | #endif 389 | 390 | #ifdef PLUGIN_094 391 | Plugin_id[x] = 94; Plugin_ptr[x++] = &Plugin_094; 392 | #endif 393 | 394 | #ifdef PLUGIN_095 395 | Plugin_id[x] = 95; Plugin_ptr[x++] = &Plugin_095; 396 | #endif 397 | 398 | #ifdef PLUGIN_096 399 | Plugin_id[x] = 96; Plugin_ptr[x++] = &Plugin_096; 400 | #endif 401 | 402 | #ifdef PLUGIN_097 403 | Plugin_id[x] = 97; Plugin_ptr[x++] = &Plugin_097; 404 | #endif 405 | 406 | #ifdef PLUGIN_098 407 | Plugin_id[x] = 98; Plugin_ptr[x++] = &Plugin_098; 408 | #endif 409 | 410 | #ifdef PLUGIN_099 411 | Plugin_id[x] = 99; Plugin_ptr[x++] = &Plugin_099; 412 | #endif 413 | 414 | #ifdef PLUGIN_100 415 | Plugin_id[x] = 100; Plugin_ptr[x++] = &Plugin_100; 416 | #endif 417 | 418 | #ifdef PLUGIN_101 419 | Plugin_id[x] = 101; Plugin_ptr[x++] = &Plugin_101; 420 | #endif 421 | 422 | #ifdef PLUGIN_102 423 | Plugin_id[x] = 102; Plugin_ptr[x++] = &Plugin_102; 424 | #endif 425 | 426 | #ifdef PLUGIN_103 427 | Plugin_id[x] = 103; Plugin_ptr[x++] = &Plugin_103; 428 | #endif 429 | 430 | #ifdef PLUGIN_104 431 | Plugin_id[x] = 104; Plugin_ptr[x++] = &Plugin_104; 432 | #endif 433 | 434 | #ifdef PLUGIN_105 435 | Plugin_id[x] = 105; Plugin_ptr[x++] = &Plugin_105; 436 | #endif 437 | 438 | #ifdef PLUGIN_106 439 | Plugin_id[x] = 106; Plugin_ptr[x++] = &Plugin_106; 440 | #endif 441 | 442 | #ifdef PLUGIN_107 443 | Plugin_id[x] = 107; Plugin_ptr[x++] = &Plugin_107; 444 | #endif 445 | 446 | #ifdef PLUGIN_108 447 | Plugin_id[x] = 108; Plugin_ptr[x++] = &Plugin_108; 448 | #endif 449 | 450 | #ifdef PLUGIN_109 451 | Plugin_id[x] = 109; Plugin_ptr[x++] = &Plugin_109; 452 | #endif 453 | 454 | #ifdef PLUGIN_110 455 | Plugin_id[x] = 110; Plugin_ptr[x++] = &Plugin_110; 456 | #endif 457 | 458 | #ifdef PLUGIN_111 459 | Plugin_id[x] = 111; Plugin_ptr[x++] = &Plugin_111; 460 | #endif 461 | 462 | #ifdef PLUGIN_112 463 | Plugin_id[x] = 112; Plugin_ptr[x++] = &Plugin_112; 464 | #endif 465 | 466 | #ifdef PLUGIN_113 467 | Plugin_id[x] = 113; Plugin_ptr[x++] = &Plugin_113; 468 | #endif 469 | 470 | #ifdef PLUGIN_114 471 | Plugin_id[x] = 114; Plugin_ptr[x++] = &Plugin_114; 472 | #endif 473 | 474 | #ifdef PLUGIN_115 475 | Plugin_id[x] = 115; Plugin_ptr[x++] = &Plugin_115; 476 | #endif 477 | 478 | #ifdef PLUGIN_116 479 | Plugin_id[x] = 116; Plugin_ptr[x++] = &Plugin_116; 480 | #endif 481 | 482 | #ifdef PLUGIN_117 483 | Plugin_id[x] = 117; Plugin_ptr[x++] = &Plugin_117; 484 | #endif 485 | 486 | #ifdef PLUGIN_118 487 | Plugin_id[x] = 118; Plugin_ptr[x++] = &Plugin_118; 488 | #endif 489 | 490 | #ifdef PLUGIN_119 491 | Plugin_id[x] = 119; Plugin_ptr[x++] = &Plugin_119; 492 | #endif 493 | 494 | #ifdef PLUGIN_120 495 | Plugin_id[x] = 120; Plugin_ptr[x++] = &Plugin_120; 496 | #endif 497 | 498 | #ifdef PLUGIN_121 499 | Plugin_id[x] = 121; Plugin_ptr[x++] = &Plugin_121; 500 | #endif 501 | 502 | #ifdef PLUGIN_122 503 | Plugin_id[x] = 122; Plugin_ptr[x++] = &Plugin_122; 504 | #endif 505 | 506 | #ifdef PLUGIN_123 507 | Plugin_id[x] = 123; Plugin_ptr[x++] = &Plugin_123; 508 | #endif 509 | 510 | #ifdef PLUGIN_124 511 | Plugin_id[x] = 124; Plugin_ptr[x++] = &Plugin_124; 512 | #endif 513 | 514 | #ifdef PLUGIN_125 515 | Plugin_id[x] = 125; Plugin_ptr[x++] = &Plugin_125; 516 | #endif 517 | 518 | #ifdef PLUGIN_126 519 | Plugin_id[x] = 126; Plugin_ptr[x++] = &Plugin_126; 520 | #endif 521 | 522 | #ifdef PLUGIN_127 523 | Plugin_id[x] = 127; Plugin_ptr[x++] = &Plugin_127; 524 | #endif 525 | 526 | #ifdef PLUGIN_128 527 | Plugin_id[x] = 128; Plugin_ptr[x++] = &Plugin_128; 528 | #endif 529 | 530 | #ifdef PLUGIN_129 531 | Plugin_id[x] = 129; Plugin_ptr[x++] = &Plugin_129; 532 | #endif 533 | 534 | #ifdef PLUGIN_130 535 | Plugin_id[x] = 130; Plugin_ptr[x++] = &Plugin_130; 536 | #endif 537 | 538 | #ifdef PLUGIN_131 539 | Plugin_id[x] = 131; Plugin_ptr[x++] = &Plugin_131; 540 | #endif 541 | 542 | #ifdef PLUGIN_132 543 | Plugin_id[x] = 132; Plugin_ptr[x++] = &Plugin_132; 544 | #endif 545 | 546 | #ifdef PLUGIN_133 547 | Plugin_id[x] = 133; Plugin_ptr[x++] = &Plugin_133; 548 | #endif 549 | 550 | #ifdef PLUGIN_134 551 | Plugin_id[x] = 134; Plugin_ptr[x++] = &Plugin_134; 552 | #endif 553 | 554 | #ifdef PLUGIN_135 555 | Plugin_id[x] = 135; Plugin_ptr[x++] = &Plugin_135; 556 | #endif 557 | 558 | #ifdef PLUGIN_136 559 | Plugin_id[x] = 136; Plugin_ptr[x++] = &Plugin_136; 560 | #endif 561 | 562 | #ifdef PLUGIN_137 563 | Plugin_id[x] = 137; Plugin_ptr[x++] = &Plugin_137; 564 | #endif 565 | 566 | #ifdef PLUGIN_138 567 | Plugin_id[x] = 138; Plugin_ptr[x++] = &Plugin_138; 568 | #endif 569 | 570 | #ifdef PLUGIN_139 571 | Plugin_id[x] = 139; Plugin_ptr[x++] = &Plugin_139; 572 | #endif 573 | 574 | #ifdef PLUGIN_140 575 | Plugin_id[x] = 140; Plugin_ptr[x++] = &Plugin_140; 576 | #endif 577 | 578 | #ifdef PLUGIN_141 579 | Plugin_id[x] = 141; Plugin_ptr[x++] = &Plugin_141; 580 | #endif 581 | 582 | #ifdef PLUGIN_142 583 | Plugin_id[x] = 142; Plugin_ptr[x++] = &Plugin_142; 584 | #endif 585 | 586 | #ifdef PLUGIN_143 587 | Plugin_id[x] = 143; Plugin_ptr[x++] = &Plugin_143; 588 | #endif 589 | 590 | #ifdef PLUGIN_144 591 | Plugin_id[x] = 144; Plugin_ptr[x++] = &Plugin_144; 592 | #endif 593 | 594 | #ifdef PLUGIN_145 595 | Plugin_id[x] = 145; Plugin_ptr[x++] = &Plugin_145; 596 | #endif 597 | 598 | #ifdef PLUGIN_146 599 | Plugin_id[x] = 146; Plugin_ptr[x++] = &Plugin_146; 600 | #endif 601 | 602 | #ifdef PLUGIN_147 603 | Plugin_id[x] = 147; Plugin_ptr[x++] = &Plugin_147; 604 | #endif 605 | 606 | #ifdef PLUGIN_148 607 | Plugin_id[x] = 148; Plugin_ptr[x++] = &Plugin_148; 608 | #endif 609 | 610 | #ifdef PLUGIN_149 611 | Plugin_id[x] = 149; Plugin_ptr[x++] = &Plugin_149; 612 | #endif 613 | 614 | #ifdef PLUGIN_150 615 | Plugin_id[x] = 150; Plugin_ptr[x++] = &Plugin_150; 616 | #endif 617 | 618 | #ifdef PLUGIN_151 619 | Plugin_id[x] = 151; Plugin_ptr[x++] = &Plugin_151; 620 | #endif 621 | 622 | #ifdef PLUGIN_152 623 | Plugin_id[x] = 152; Plugin_ptr[x++] = &Plugin_152; 624 | #endif 625 | 626 | #ifdef PLUGIN_153 627 | Plugin_id[x] = 153; Plugin_ptr[x++] = &Plugin_153; 628 | #endif 629 | 630 | #ifdef PLUGIN_154 631 | Plugin_id[x] = 154; Plugin_ptr[x++] = &Plugin_154; 632 | #endif 633 | 634 | #ifdef PLUGIN_155 635 | Plugin_id[x] = 155; Plugin_ptr[x++] = &Plugin_155; 636 | #endif 637 | 638 | #ifdef PLUGIN_156 639 | Plugin_id[x] = 156; Plugin_ptr[x++] = &Plugin_156; 640 | #endif 641 | 642 | #ifdef PLUGIN_157 643 | Plugin_id[x] = 157; Plugin_ptr[x++] = &Plugin_157; 644 | #endif 645 | 646 | #ifdef PLUGIN_158 647 | Plugin_id[x] = 158; Plugin_ptr[x++] = &Plugin_158; 648 | #endif 649 | 650 | #ifdef PLUGIN_159 651 | Plugin_id[x] = 159; Plugin_ptr[x++] = &Plugin_159; 652 | #endif 653 | 654 | #ifdef PLUGIN_160 655 | Plugin_id[x] = 160; Plugin_ptr[x++] = &Plugin_160; 656 | #endif 657 | 658 | #ifdef PLUGIN_161 659 | Plugin_id[x] = 161; Plugin_ptr[x++] = &Plugin_161; 660 | #endif 661 | 662 | #ifdef PLUGIN_162 663 | Plugin_id[x] = 162; Plugin_ptr[x++] = &Plugin_162; 664 | #endif 665 | 666 | #ifdef PLUGIN_163 667 | Plugin_id[x] = 163; Plugin_ptr[x++] = &Plugin_163; 668 | #endif 669 | 670 | #ifdef PLUGIN_164 671 | Plugin_id[x] = 164; Plugin_ptr[x++] = &Plugin_164; 672 | #endif 673 | 674 | #ifdef PLUGIN_165 675 | Plugin_id[x] = 165; Plugin_ptr[x++] = &Plugin_165; 676 | #endif 677 | 678 | #ifdef PLUGIN_166 679 | Plugin_id[x] = 166; Plugin_ptr[x++] = &Plugin_166; 680 | #endif 681 | 682 | #ifdef PLUGIN_167 683 | Plugin_id[x] = 167; Plugin_ptr[x++] = &Plugin_167; 684 | #endif 685 | 686 | #ifdef PLUGIN_168 687 | Plugin_id[x] = 168; Plugin_ptr[x++] = &Plugin_168; 688 | #endif 689 | 690 | #ifdef PLUGIN_169 691 | Plugin_id[x] = 169; Plugin_ptr[x++] = &Plugin_169; 692 | #endif 693 | 694 | #ifdef PLUGIN_170 695 | Plugin_id[x] = 170; Plugin_ptr[x++] = &Plugin_170; 696 | #endif 697 | 698 | #ifdef PLUGIN_171 699 | Plugin_id[x] = 171; Plugin_ptr[x++] = &Plugin_171; 700 | #endif 701 | 702 | #ifdef PLUGIN_172 703 | Plugin_id[x] = 172; Plugin_ptr[x++] = &Plugin_172; 704 | #endif 705 | 706 | #ifdef PLUGIN_173 707 | Plugin_id[x] = 173; Plugin_ptr[x++] = &Plugin_173; 708 | #endif 709 | 710 | #ifdef PLUGIN_174 711 | Plugin_id[x] = 174; Plugin_ptr[x++] = &Plugin_174; 712 | #endif 713 | 714 | #ifdef PLUGIN_175 715 | Plugin_id[x] = 175; Plugin_ptr[x++] = &Plugin_175; 716 | #endif 717 | 718 | #ifdef PLUGIN_176 719 | Plugin_id[x] = 176; Plugin_ptr[x++] = &Plugin_176; 720 | #endif 721 | 722 | #ifdef PLUGIN_177 723 | Plugin_id[x] = 177; Plugin_ptr[x++] = &Plugin_177; 724 | #endif 725 | 726 | #ifdef PLUGIN_178 727 | Plugin_id[x] = 178; Plugin_ptr[x++] = &Plugin_178; 728 | #endif 729 | 730 | #ifdef PLUGIN_179 731 | Plugin_id[x] = 179; Plugin_ptr[x++] = &Plugin_179; 732 | #endif 733 | 734 | #ifdef PLUGIN_180 735 | Plugin_id[x] = 180; Plugin_ptr[x++] = &Plugin_180; 736 | #endif 737 | 738 | #ifdef PLUGIN_181 739 | Plugin_id[x] = 181; Plugin_ptr[x++] = &Plugin_181; 740 | #endif 741 | 742 | #ifdef PLUGIN_182 743 | Plugin_id[x] = 182; Plugin_ptr[x++] = &Plugin_182; 744 | #endif 745 | 746 | #ifdef PLUGIN_183 747 | Plugin_id[x] = 183; Plugin_ptr[x++] = &Plugin_183; 748 | #endif 749 | 750 | #ifdef PLUGIN_184 751 | Plugin_id[x] = 184; Plugin_ptr[x++] = &Plugin_184; 752 | #endif 753 | 754 | #ifdef PLUGIN_185 755 | Plugin_id[x] = 185; Plugin_ptr[x++] = &Plugin_185; 756 | #endif 757 | 758 | #ifdef PLUGIN_186 759 | Plugin_id[x] = 186; Plugin_ptr[x++] = &Plugin_186; 760 | #endif 761 | 762 | #ifdef PLUGIN_187 763 | Plugin_id[x] = 187; Plugin_ptr[x++] = &Plugin_187; 764 | #endif 765 | 766 | #ifdef PLUGIN_188 767 | Plugin_id[x] = 188; Plugin_ptr[x++] = &Plugin_188; 768 | #endif 769 | 770 | #ifdef PLUGIN_189 771 | Plugin_id[x] = 189; Plugin_ptr[x++] = &Plugin_189; 772 | #endif 773 | 774 | #ifdef PLUGIN_190 775 | Plugin_id[x] = 190; Plugin_ptr[x++] = &Plugin_190; 776 | #endif 777 | 778 | #ifdef PLUGIN_191 779 | Plugin_id[x] = 191; Plugin_ptr[x++] = &Plugin_191; 780 | #endif 781 | 782 | #ifdef PLUGIN_192 783 | Plugin_id[x] = 192; Plugin_ptr[x++] = &Plugin_192; 784 | #endif 785 | 786 | #ifdef PLUGIN_193 787 | Plugin_id[x] = 193; Plugin_ptr[x++] = &Plugin_193; 788 | #endif 789 | 790 | #ifdef PLUGIN_194 791 | Plugin_id[x] = 194; Plugin_ptr[x++] = &Plugin_194; 792 | #endif 793 | 794 | #ifdef PLUGIN_195 795 | Plugin_id[x] = 195; Plugin_ptr[x++] = &Plugin_195; 796 | #endif 797 | 798 | #ifdef PLUGIN_196 799 | Plugin_id[x] = 196; Plugin_ptr[x++] = &Plugin_196; 800 | #endif 801 | 802 | #ifdef PLUGIN_197 803 | Plugin_id[x] = 197; Plugin_ptr[x++] = &Plugin_197; 804 | #endif 805 | 806 | #ifdef PLUGIN_198 807 | Plugin_id[x] = 198; Plugin_ptr[x++] = &Plugin_198; 808 | #endif 809 | 810 | #ifdef PLUGIN_199 811 | Plugin_id[x] = 199; Plugin_ptr[x++] = &Plugin_199; 812 | #endif 813 | 814 | #ifdef PLUGIN_200 815 | Plugin_id[x] = 200; Plugin_ptr[x++] = &Plugin_200; 816 | #endif 817 | 818 | #ifdef PLUGIN_201 819 | Plugin_id[x] = 201; Plugin_ptr[x++] = &Plugin_201; 820 | #endif 821 | 822 | #ifdef PLUGIN_202 823 | Plugin_id[x] = 202; Plugin_ptr[x++] = &Plugin_202; 824 | #endif 825 | 826 | #ifdef PLUGIN_203 827 | Plugin_id[x] = 203; Plugin_ptr[x++] = &Plugin_203; 828 | #endif 829 | 830 | #ifdef PLUGIN_204 831 | Plugin_id[x] = 204; Plugin_ptr[x++] = &Plugin_204; 832 | #endif 833 | 834 | #ifdef PLUGIN_205 835 | Plugin_id[x] = 205; Plugin_ptr[x++] = &Plugin_205; 836 | #endif 837 | 838 | #ifdef PLUGIN_206 839 | Plugin_id[x] = 206; Plugin_ptr[x++] = &Plugin_206; 840 | #endif 841 | 842 | #ifdef PLUGIN_207 843 | Plugin_id[x] = 207; Plugin_ptr[x++] = &Plugin_207; 844 | #endif 845 | 846 | #ifdef PLUGIN_208 847 | Plugin_id[x] = 208; Plugin_ptr[x++] = &Plugin_208; 848 | #endif 849 | 850 | #ifdef PLUGIN_209 851 | Plugin_id[x] = 209; Plugin_ptr[x++] = &Plugin_209; 852 | #endif 853 | 854 | #ifdef PLUGIN_210 855 | Plugin_id[x] = 210; Plugin_ptr[x++] = &Plugin_210; 856 | #endif 857 | 858 | #ifdef PLUGIN_211 859 | Plugin_id[x] = 211; Plugin_ptr[x++] = &Plugin_211; 860 | #endif 861 | 862 | #ifdef PLUGIN_212 863 | Plugin_id[x] = 212; Plugin_ptr[x++] = &Plugin_212; 864 | #endif 865 | 866 | #ifdef PLUGIN_213 867 | Plugin_id[x] = 213; Plugin_ptr[x++] = &Plugin_213; 868 | #endif 869 | 870 | #ifdef PLUGIN_214 871 | Plugin_id[x] = 214; Plugin_ptr[x++] = &Plugin_214; 872 | #endif 873 | 874 | #ifdef PLUGIN_215 875 | Plugin_id[x] = 215; Plugin_ptr[x++] = &Plugin_215; 876 | #endif 877 | 878 | #ifdef PLUGIN_216 879 | Plugin_id[x] = 216; Plugin_ptr[x++] = &Plugin_216; 880 | #endif 881 | 882 | #ifdef PLUGIN_217 883 | Plugin_id[x] = 217; Plugin_ptr[x++] = &Plugin_217; 884 | #endif 885 | 886 | #ifdef PLUGIN_218 887 | Plugin_id[x] = 218; Plugin_ptr[x++] = &Plugin_218; 888 | #endif 889 | 890 | #ifdef PLUGIN_219 891 | Plugin_id[x] = 219; Plugin_ptr[x++] = &Plugin_219; 892 | #endif 893 | 894 | #ifdef PLUGIN_220 895 | Plugin_id[x] = 220; Plugin_ptr[x++] = &Plugin_220; 896 | #endif 897 | 898 | #ifdef PLUGIN_221 899 | Plugin_id[x] = 221; Plugin_ptr[x++] = &Plugin_221; 900 | #endif 901 | 902 | #ifdef PLUGIN_222 903 | Plugin_id[x] = 222; Plugin_ptr[x++] = &Plugin_222; 904 | #endif 905 | 906 | #ifdef PLUGIN_223 907 | Plugin_id[x] = 223; Plugin_ptr[x++] = &Plugin_223; 908 | #endif 909 | 910 | #ifdef PLUGIN_224 911 | Plugin_id[x] = 224; Plugin_ptr[x++] = &Plugin_224; 912 | #endif 913 | 914 | #ifdef PLUGIN_225 915 | Plugin_id[x] = 225; Plugin_ptr[x++] = &Plugin_225; 916 | #endif 917 | 918 | #ifdef PLUGIN_226 919 | Plugin_id[x] = 226; Plugin_ptr[x++] = &Plugin_226; 920 | #endif 921 | 922 | #ifdef PLUGIN_227 923 | Plugin_id[x] = 227; Plugin_ptr[x++] = &Plugin_227; 924 | #endif 925 | 926 | #ifdef PLUGIN_228 927 | Plugin_id[x] = 228; Plugin_ptr[x++] = &Plugin_228; 928 | #endif 929 | 930 | #ifdef PLUGIN_229 931 | Plugin_id[x] = 229; Plugin_ptr[x++] = &Plugin_229; 932 | #endif 933 | 934 | #ifdef PLUGIN_230 935 | Plugin_id[x] = 230; Plugin_ptr[x++] = &Plugin_230; 936 | #endif 937 | 938 | #ifdef PLUGIN_231 939 | Plugin_id[x] = 231; Plugin_ptr[x++] = &Plugin_231; 940 | #endif 941 | 942 | #ifdef PLUGIN_232 943 | Plugin_id[x] = 232; Plugin_ptr[x++] = &Plugin_232; 944 | #endif 945 | 946 | #ifdef PLUGIN_233 947 | Plugin_id[x] = 233; Plugin_ptr[x++] = &Plugin_233; 948 | #endif 949 | 950 | #ifdef PLUGIN_234 951 | Plugin_id[x] = 234; Plugin_ptr[x++] = &Plugin_234; 952 | #endif 953 | 954 | #ifdef PLUGIN_235 955 | Plugin_id[x] = 235; Plugin_ptr[x++] = &Plugin_235; 956 | #endif 957 | 958 | #ifdef PLUGIN_236 959 | Plugin_id[x] = 236; Plugin_ptr[x++] = &Plugin_236; 960 | #endif 961 | 962 | #ifdef PLUGIN_237 963 | Plugin_id[x] = 237; Plugin_ptr[x++] = &Plugin_237; 964 | #endif 965 | 966 | #ifdef PLUGIN_238 967 | Plugin_id[x] = 238; Plugin_ptr[x++] = &Plugin_238; 968 | #endif 969 | 970 | #ifdef PLUGIN_239 971 | Plugin_id[x] = 239; Plugin_ptr[x++] = &Plugin_239; 972 | #endif 973 | 974 | #ifdef PLUGIN_240 975 | Plugin_id[x] = 240; Plugin_ptr[x++] = &Plugin_240; 976 | #endif 977 | 978 | #ifdef PLUGIN_241 979 | Plugin_id[x] = 241; Plugin_ptr[x++] = &Plugin_241; 980 | #endif 981 | 982 | #ifdef PLUGIN_242 983 | Plugin_id[x] = 242; Plugin_ptr[x++] = &Plugin_242; 984 | #endif 985 | 986 | #ifdef PLUGIN_243 987 | Plugin_id[x] = 243; Plugin_ptr[x++] = &Plugin_243; 988 | #endif 989 | 990 | #ifdef PLUGIN_244 991 | Plugin_id[x] = 244; Plugin_ptr[x++] = &Plugin_244; 992 | #endif 993 | 994 | #ifdef PLUGIN_245 995 | Plugin_id[x] = 245; Plugin_ptr[x++] = &Plugin_245; 996 | #endif 997 | 998 | #ifdef PLUGIN_246 999 | Plugin_id[x] = 246; Plugin_ptr[x++] = &Plugin_246; 1000 | #endif 1001 | 1002 | #ifdef PLUGIN_247 1003 | Plugin_id[x] = 247; Plugin_ptr[x++] = &Plugin_247; 1004 | #endif 1005 | 1006 | #ifdef PLUGIN_248 1007 | Plugin_id[x] = 248; Plugin_ptr[x++] = &Plugin_248; 1008 | #endif 1009 | 1010 | #ifdef PLUGIN_249 1011 | Plugin_id[x] = 249; Plugin_ptr[x++] = &Plugin_249; 1012 | #endif 1013 | 1014 | #ifdef PLUGIN_250 1015 | Plugin_id[x] = 250; Plugin_ptr[x++] = &Plugin_250; 1016 | #endif 1017 | 1018 | #ifdef PLUGIN_251 1019 | Plugin_id[x] = 251; Plugin_ptr[x++] = &Plugin_251; 1020 | #endif 1021 | 1022 | #ifdef PLUGIN_252 1023 | Plugin_id[x] = 252; Plugin_ptr[x++] = &Plugin_252; 1024 | #endif 1025 | 1026 | #ifdef PLUGIN_253 1027 | Plugin_id[x] = 253; Plugin_ptr[x++] = &Plugin_253; 1028 | #endif 1029 | 1030 | #ifdef PLUGIN_254 1031 | Plugin_id[x] = 254; Plugin_ptr[x++] = &Plugin_254; 1032 | #endif 1033 | 1034 | #ifdef PLUGIN_255 1035 | Plugin_id[x] = 255; Plugin_ptr[x++] = &Plugin_255; 1036 | #endif 1037 | 1038 | PluginCall(PLUGIN_DEVICE_ADD, 0, dummyString); 1039 | PluginCall(PLUGIN_INIT_ALL, 0, dummyString); 1040 | 1041 | } 1042 | 1043 | 1044 | /*********************************************************************************************\ 1045 | * Function call to all or specific plugins 1046 | \*********************************************************************************************/ 1047 | byte PluginCall(byte Function, struct EventStruct *event, String& str) 1048 | { 1049 | int x; 1050 | struct EventStruct TempEvent; 1051 | 1052 | if (event == 0) 1053 | event = &TempEvent; 1054 | 1055 | switch (Function) 1056 | { 1057 | // Unconditional calls to all plugins 1058 | case PLUGIN_DEVICE_ADD: 1059 | for (x = 0; x < PLUGIN_MAX; x++) 1060 | if (Plugin_id[x] != 0) 1061 | Plugin_ptr[x](Function, event, str); 1062 | return true; 1063 | break; 1064 | 1065 | // Call to all plugins. Return at first match 1066 | case PLUGIN_WRITE: 1067 | for (x = 0; x < PLUGIN_MAX; x++) 1068 | if (Plugin_id[x] != 0) 1069 | if (Plugin_ptr[x](Function, event, str)) 1070 | return true; 1071 | break; 1072 | 1073 | // Call to all plugins used in a task. Return at first match 1074 | case PLUGIN_SERIAL_IN: 1075 | case PLUGIN_UDP_IN: 1076 | { 1077 | for (byte y = 0; y < TASKS_MAX; y++) 1078 | { 1079 | if (Settings.TaskDeviceNumber[y] != 0) 1080 | { 1081 | for (x = 0; x < PLUGIN_MAX; x++) 1082 | { 1083 | if (Plugin_id[x] == Settings.TaskDeviceNumber[y]) 1084 | { 1085 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]); 1086 | TempEvent.TaskIndex = y; 1087 | TempEvent.BaseVarIndex = y * VARS_PER_TASK; 1088 | TempEvent.idx = Settings.TaskDeviceID[y]; 1089 | TempEvent.sensorType = Device[DeviceIndex].VType; 1090 | if (Plugin_ptr[x](Function, event, str)) 1091 | return true; 1092 | } 1093 | } 1094 | } 1095 | } 1096 | return false; 1097 | break; 1098 | } 1099 | 1100 | // Call to all plugins that are used in a task 1101 | case PLUGIN_ONCE_A_SECOND: 1102 | case PLUGIN_TEN_PER_SECOND: 1103 | case PLUGIN_INIT_ALL: 1104 | case PLUGIN_CLOCK_IN: 1105 | case PLUGIN_EVENT_OUT: 1106 | { 1107 | if (Function == PLUGIN_INIT_ALL) 1108 | Function = PLUGIN_INIT; 1109 | for (byte y = 0; y < TASKS_MAX; y++) 1110 | { 1111 | if (Settings.TaskDeviceNumber[y] != 0) 1112 | { 1113 | if (Settings.TaskDeviceDataFeed[y] == 0) // these calls only to tasks with local feed 1114 | { 1115 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[y]); 1116 | TempEvent.TaskIndex = y; 1117 | TempEvent.BaseVarIndex = y * VARS_PER_TASK; 1118 | TempEvent.idx = Settings.TaskDeviceID[y]; 1119 | TempEvent.sensorType = Device[DeviceIndex].VType; 1120 | TempEvent.OriginTaskIndex = event->TaskIndex; 1121 | for (x = 0; x < PLUGIN_MAX; x++) 1122 | { 1123 | if (Plugin_id[x] == Settings.TaskDeviceNumber[y]) 1124 | { 1125 | Plugin_ptr[x](Function, &TempEvent, str); 1126 | } 1127 | } 1128 | } 1129 | } 1130 | } 1131 | return true; 1132 | break; 1133 | } 1134 | 1135 | // Call to specific plugin that is used for current task 1136 | case PLUGIN_INIT: 1137 | case PLUGIN_WEBFORM_LOAD: 1138 | case PLUGIN_WEBFORM_SAVE: 1139 | case PLUGIN_WEBFORM_SHOW_VALUES: 1140 | case PLUGIN_WEBFORM_SHOW_CONFIG: 1141 | case PLUGIN_GET_DEVICEVALUENAMES: 1142 | case PLUGIN_READ: 1143 | for (x = 0; x < PLUGIN_MAX; x++) 1144 | { 1145 | if ((Plugin_id[x] != 0 ) && (Plugin_id[x] == Settings.TaskDeviceNumber[event->TaskIndex])) 1146 | { 1147 | event->BaseVarIndex = event->TaskIndex * VARS_PER_TASK; 1148 | return Plugin_ptr[x](Function, event, str); 1149 | } 1150 | } 1151 | return false; 1152 | break; 1153 | 1154 | }// case 1155 | return false; 1156 | } 1157 | -------------------------------------------------------------------------------- /src/__ReleaseNotes.ino: -------------------------------------------------------------------------------- 1 | // R154 26-08-2017 2 | // Removed pin select D4 from the list as it is used for SD Card 3 | // Fixed Dallas plugin for AVR 4 | 5 | // R153 25-08-2017 6 | // Added nodetype to self. 7 | // Minor cosmetic GUI fixes 8 | 9 | // R152 21-08-2017 10 | // Fixed a bug with getting NTP time when nodelist is active and fixed a socket issue when combined with MQTT 11 | // Dummy WebServer class to mimic WebServer.arg calls from plugins 12 | // Fixed GUI formatting bug when NPT disabled 13 | // Added some GUI handlers from the Mega branch 14 | // Added NodeType in main screen 15 | 16 | // R151 14-08-2017 17 | // Update Mini Dashboard 18 | 19 | // R150 12-08-2017 20 | // Fixed some webgui bugs and reduced RAM usage 21 | // Fixed syslog feature 22 | // Added some plugins: Dallas, DHT, DHT12 23 | // Added authentication for C001 (Base64 lib added) 24 | // Added Mini Dashboard 25 | 26 | // R147 08-12-2016 27 | // First alpha version (Proof Of Concept!) 28 | // Based on ESP Easy R147 29 | 30 | // Limited on several features: 31 | // SSDP is not implemented 32 | // No SPIFFS but using SD card instead. So it does not run without an SD card fitted! 33 | // Reused existing UDP socket for NTP, due to shortage of W5100 sockets. 34 | 35 | // Known issues: 36 | // WD message was incorrect, failures reported as freemem, freemem is missing, workaround is using string object... 37 | // when timed reboot, system does not reboot ??? 38 | --------------------------------------------------------------------------------