├── Command.ino ├── Controller.ino ├── ESPEasy.ino ├── Hardware.ino ├── Misc.ino ├── Networking.ino ├── README.md ├── Serial.ino ├── WebServer.ino ├── Wifi.ino ├── _C001_Domoticz_HTTP.ino ├── _C002_Domoticz_MQTT.ino ├── _C003_Nodo_Telnet.ino ├── _C004_ThingSpeak.ino ├── _C005_MQTT.ino ├── _C006_PiDome.ino ├── _C007_EmonCMS.ino ├── _C008_HTTP.ino ├── _C009_FHEM_HTTP.ino ├── _C010_UDP.ino ├── _C011_HTTP_Adv.ino ├── _N001_Email.ino ├── _N002_Buzzer.ino ├── _P001_Switch.ino ├── _P002_ADC.ino ├── _P003_Pulse.ino ├── _P004_Dallas.ino ├── _P005_DHT.ino ├── _P006_BMP085.ino ├── _P007_PCF8591.ino ├── _P008_RFID.ino ├── _P009_MCP.ino ├── _P010_BH1750.ino ├── _P011_PME.ino ├── _P012_LCD.ino ├── _P013_HCSR04.ino ├── _P014_SI7021.ino ├── _P015_TLS2561.ino ├── _P016_IR.ino ├── _P017_PN532.ino ├── _P018_Dust.ino ├── _P019_PCF8574.ino ├── _P020_Ser2Net.ino ├── _P021_Level.ino ├── _P022_PCA9685.ino ├── _P023_OLED.ino ├── _P024_MLX90614.ino ├── _P025_ADS1115.ino ├── _P026_Sysinfo.ino ├── _P027_INA219.ino ├── _P028_BME280.ino ├── _P029_Output.ino ├── _P030_BMP280.ino ├── _P031_SHT1X.ino ├── _P032_MS5611.ino ├── _P033_Dummy.ino ├── _P034_DHT12.ino ├── _P035_IRTX.ino ├── _P036_FrameOLED.ino ├── _P037_MQTTImport.ino ├── _P038_NeoPixel.ino ├── _P039_Thermocouple.ino ├── _P040_ID12.ino ├── _P041_NeoClock.ino ├── _P042_Candle.ino ├── _P043_ClkOutput.ino ├── _P044_P1WifiGateway.ino ├── __CPlugin.ino ├── __NPlugin.ino ├── __Plugin.ino └── __ReleaseNotes.ino /Controller.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Interface for Sending to Controllers 3 | //******************************************************************************** 4 | boolean sendData(struct EventStruct *event) 5 | { 6 | LoadTaskSettings(event->TaskIndex); 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 | for (byte x=0; x < CONTROLLER_MAX; x++) 34 | { 35 | event->ControllerIndex = x; 36 | event->idx = Settings.TaskDeviceID[x][event->TaskIndex]; 37 | 38 | if (Settings.TaskDeviceSendData[event->ControllerIndex][event->TaskIndex] && Settings.ControllerEnabled[event->ControllerIndex] && Settings.Protocol[event->ControllerIndex]) 39 | { 40 | event->ProtocolIndex = getProtocolIndex(Settings.Protocol[event->ControllerIndex]); 41 | CPlugin_ptr[event->ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString); 42 | } 43 | } 44 | 45 | PluginCall(PLUGIN_EVENT_OUT, event, dummyString); 46 | lastSend = millis(); 47 | } 48 | 49 | 50 | /*********************************************************************************************\ 51 | * Handle incoming MQTT messages 52 | \*********************************************************************************************/ 53 | // handle MQTT messages 54 | void callback(char* c_topic, byte* b_payload, unsigned int length) { 55 | char log[256]; 56 | char c_payload[256]; 57 | strncpy(c_payload,(char*)b_payload,length); 58 | c_payload[length] = 0; 59 | statusLED(true); 60 | 61 | sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic); 62 | addLog(LOG_LEVEL_DEBUG, log); 63 | sprintf_P(log, PSTR("%s%s"), "MQTT : Payload: ", c_payload); 64 | addLog(LOG_LEVEL_DEBUG, log); 65 | 66 | struct EventStruct TempEvent; 67 | TempEvent.String1 = c_topic; 68 | TempEvent.String2 = c_payload; 69 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]); 70 | CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString); 71 | } 72 | 73 | 74 | /*********************************************************************************************\ 75 | * Connect to MQTT message broker 76 | \*********************************************************************************************/ 77 | void MQTTConnect() 78 | { 79 | ControllerSettingsStruct ControllerSettings; 80 | LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0 81 | 82 | IPAddress MQTTBrokerIP(ControllerSettings.IP); 83 | MQTTclient.setServer(MQTTBrokerIP, ControllerSettings.Port); 84 | MQTTclient.setCallback(callback); 85 | 86 | // MQTT needs a unique clientname to subscribe to broker 87 | String clientid = "ESPClient"; 88 | clientid += Settings.Unit; 89 | String subscribeTo = ""; 90 | 91 | String LWTTopic = ControllerSettings.Subscribe; 92 | LWTTopic.replace(F("/#"), F("/status")); 93 | LWTTopic.replace(F("%sysname%"), Settings.Name); 94 | 95 | for (byte x = 1; x < 3; x++) 96 | { 97 | String log = ""; 98 | boolean MQTTresult = false; 99 | 100 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 101 | MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser[0], SecuritySettings.ControllerPassword[0], LWTTopic.c_str(), 0, 0, "Connection Lost"); 102 | else 103 | MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, "Connection Lost"); 104 | 105 | if (MQTTresult) 106 | { 107 | log = F("MQTT : Connected to broker"); 108 | addLog(LOG_LEVEL_INFO, log); 109 | subscribeTo = ControllerSettings.Subscribe; 110 | subscribeTo.replace(F("%sysname%"), Settings.Name); 111 | MQTTclient.subscribe(subscribeTo.c_str()); 112 | log = F("Subscribed to: "); 113 | log += subscribeTo; 114 | addLog(LOG_LEVEL_INFO, log); 115 | break; // end loop if succesfull 116 | } 117 | else 118 | { 119 | log = F("MQTT : Failed to connected to broker"); 120 | addLog(LOG_LEVEL_ERROR, log); 121 | } 122 | 123 | delay(500); 124 | } 125 | } 126 | 127 | 128 | /*********************************************************************************************\ 129 | * Check connection MQTT message broker 130 | \*********************************************************************************************/ 131 | void MQTTCheck() 132 | { 133 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol[0]); 134 | if (Protocol[ProtocolIndex].usesMQTT) 135 | if (!MQTTclient.connected()) 136 | { 137 | String log = F("MQTT : Connection lost"); 138 | addLog(LOG_LEVEL_ERROR, log); 139 | connectionFailures += 2; 140 | MQTTclient.disconnect(); 141 | delay(1000); 142 | MQTTConnect(); 143 | } 144 | else if (connectionFailures) 145 | connectionFailures--; 146 | } 147 | 148 | 149 | /*********************************************************************************************\ 150 | * Send status info to request source 151 | \*********************************************************************************************/ 152 | 153 | void SendStatus(byte source, String status) 154 | { 155 | switch(source) 156 | { 157 | case VALUE_SOURCE_HTTP: 158 | if (printToWeb) 159 | printWebString += status; 160 | break; 161 | case VALUE_SOURCE_MQTT: 162 | MQTTStatus(status); 163 | break; 164 | case VALUE_SOURCE_SERIAL: 165 | Serial.println(status); 166 | break; 167 | } 168 | } 169 | 170 | 171 | /*********************************************************************************************\ 172 | * Send status info back to channel where request came from 173 | \*********************************************************************************************/ 174 | void MQTTStatus(String& status) 175 | { 176 | ControllerSettingsStruct ControllerSettings; 177 | LoadControllerSettings(0, (byte*)&ControllerSettings, sizeof(ControllerSettings)); // todo index is now fixed to 0 178 | 179 | String pubname = ControllerSettings.Subscribe; 180 | pubname.replace(F("/#"), F("/status")); 181 | pubname.replace(F("%sysname%"), Settings.Name); 182 | MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag); 183 | } 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /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 | // configure hardware pins according to eeprom settings. 30 | if (Settings.Pin_i2c_sda != -1) 31 | { 32 | String log = F("INIT : I2C"); 33 | addLog(LOG_LEVEL_INFO, log); 34 | Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl); 35 | if(Settings.WireClockStretchLimit) 36 | { 37 | String log = F("INIT : I2C custom clockstretchlimit:"); 38 | log += Settings.WireClockStretchLimit; 39 | addLog(LOG_LEVEL_INFO, log); 40 | Wire.setClockStretchLimit(Settings.WireClockStretchLimit); 41 | } 42 | } 43 | 44 | // I2C Watchdog boot status check 45 | if (Settings.WDI2CAddress != 0) 46 | { 47 | delay(500); 48 | Wire.beginTransmission(Settings.WDI2CAddress); 49 | Wire.write(0x83); // command to set pointer 50 | Wire.write(17); // pointer value to status byte 51 | Wire.endTransmission(); 52 | 53 | Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1); 54 | if (Wire.available()) 55 | { 56 | byte status = Wire.read(); 57 | if (status & 0x1) 58 | { 59 | String log = F("INIT : Reset by WD!"); 60 | addLog(LOG_LEVEL_ERROR, log); 61 | lastBootCause = BOOT_CAUSE_EXT_WD; 62 | } 63 | } 64 | } 65 | 66 | // SPI Init 67 | if (Settings.InitSPI) 68 | { 69 | SPI.setHwCs(false); 70 | SPI.begin(); 71 | String log = F("INIT : SPI Init (without CS)"); 72 | addLog(LOG_LEVEL_INFO, log); 73 | } 74 | else 75 | { 76 | String log = F("INIT : SPI not enabled"); 77 | addLog(LOG_LEVEL_INFO, log); 78 | } 79 | 80 | if (Settings.Pin_sd_cs > 0) 81 | { 82 | if (SD.begin(Settings.Pin_sd_cs)) 83 | { 84 | String log = F("SD : Init OK"); 85 | addLog(LOG_LEVEL_INFO, log); 86 | } 87 | else 88 | { 89 | String log = F("SD : Init failed"); 90 | addLog(LOG_LEVEL_ERROR, log); 91 | } 92 | } 93 | 94 | } 95 | 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPEasyMega 2 | 3 | This is now in the mainrepo under the mega-branch. Please go there: https://github.com/letscontrolit/ESPEasy/tree/mega 4 | 5 | -------------------------------------------------------------------------------- /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 | yield(); 15 | SerialInByte = Serial.read(); 16 | if (SerialInByte == 255) // binary data... 17 | { 18 | Serial.flush(); 19 | return; 20 | } 21 | 22 | if (isprint(SerialInByte)) 23 | { 24 | if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits 25 | InputBuffer_Serial[SerialInByteCounter++] = SerialInByte; 26 | } 27 | 28 | if (SerialInByte == '\n') 29 | { 30 | InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed 31 | Serial.write('>'); 32 | Serial.println(InputBuffer_Serial); 33 | String action = InputBuffer_Serial; 34 | struct EventStruct TempEvent; 35 | parseCommandString(&TempEvent, action); 36 | TempEvent.Source = VALUE_SOURCE_SERIAL; 37 | if (!PluginCall(PLUGIN_WRITE, &TempEvent, action)) 38 | ExecuteCommand(VALUE_SOURCE_SERIAL, InputBuffer_Serial); 39 | SerialInByteCounter = 0; 40 | InputBuffer_Serial[0] = 0; // serial data processed, clear buffer 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Wifi.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Set Wifi AP Mode config 3 | //******************************************************************************** 4 | void WifiAPconfig() 5 | { 6 | // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! 7 | char ap_ssid[20]; 8 | ap_ssid[0] = 0; 9 | strcpy(ap_ssid, "ESP_"); 10 | sprintf_P(ap_ssid, PSTR("%s%u"), ap_ssid, Settings.Unit); 11 | // setup ssid for AP Mode when needed 12 | WiFi.softAP(ap_ssid, SecuritySettings.WifiAPKey); 13 | // We start in STA mode 14 | WiFi.mode(WIFI_STA); 15 | } 16 | 17 | 18 | //******************************************************************************** 19 | // Set Wifi AP Mode 20 | //******************************************************************************** 21 | void WifiAPMode(boolean state) 22 | { 23 | if (state) 24 | { 25 | AP_Mode = true; 26 | WiFi.mode(WIFI_AP_STA); 27 | } 28 | else 29 | { 30 | AP_Mode = false; 31 | WiFi.mode(WIFI_STA); 32 | } 33 | } 34 | 35 | 36 | //******************************************************************************** 37 | // Connect to Wifi AP 38 | //******************************************************************************** 39 | boolean WifiConnect(boolean primary, byte connectAttempts) 40 | { 41 | String log = ""; 42 | 43 | char hostName[sizeof(Settings.Name)]; 44 | strcpy(hostName,Settings.Name); 45 | for(byte x=0; x< sizeof(hostName); x++) 46 | if (hostName[x] == ' ') 47 | hostName[x] = '-'; 48 | wifi_station_set_hostname(hostName); 49 | 50 | if (Settings.IP[0] != 0 && Settings.IP[0] != 255) 51 | { 52 | char str[20]; 53 | sprintf_P(str, PSTR("%u.%u.%u.%u"), Settings.IP[0], Settings.IP[1], Settings.IP[2], Settings.IP[3]); 54 | log = F("IP : Static IP :"); 55 | log += str; 56 | addLog(LOG_LEVEL_INFO, log); 57 | IPAddress ip = Settings.IP; 58 | IPAddress gw = Settings.Gateway; 59 | IPAddress subnet = Settings.Subnet; 60 | IPAddress dns = Settings.DNS; 61 | WiFi.config(ip, gw, subnet, dns); 62 | } 63 | 64 | 65 | if (WiFi.status() != WL_CONNECTED) 66 | { 67 | if ((SecuritySettings.WifiSSID[0] != 0) && (strcasecmp(SecuritySettings.WifiSSID, "ssid") != 0)) 68 | { 69 | for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++) 70 | { 71 | log = F("WIFI : Connecting... "); 72 | log += tryConnect; 73 | addLog(LOG_LEVEL_INFO, log); 74 | 75 | if (tryConnect == 1) 76 | { 77 | if (primary) 78 | WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey); 79 | else 80 | WiFi.begin(SecuritySettings.WifiSSID2, SecuritySettings.WifiKey2); 81 | } 82 | else 83 | WiFi.begin(); 84 | 85 | for (byte x = 0; x < 20; x++) 86 | { 87 | if (WiFi.status() != WL_CONNECTED) 88 | { 89 | delay(500); 90 | } 91 | else 92 | break; 93 | } 94 | if (WiFi.status() == WL_CONNECTED) 95 | { 96 | log = F("WIFI : Connected!"); 97 | addLog(LOG_LEVEL_INFO, log); 98 | break; 99 | } 100 | else 101 | { 102 | log = F("WIFI : Disconnecting!"); 103 | addLog(LOG_LEVEL_INFO, log); 104 | ETS_UART_INTR_DISABLE(); 105 | wifi_station_disconnect(); 106 | ETS_UART_INTR_ENABLE(); 107 | delay(1000); 108 | } 109 | } 110 | 111 | // fix ip if last octet is set 112 | if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255) 113 | { 114 | IPAddress ip = WiFi.localIP(); 115 | IPAddress gw = WiFi.gatewayIP(); 116 | IPAddress subnet = WiFi.subnetMask(); 117 | ip[3] = Settings.IP_Octet; 118 | log = F("IP : Fixed IP :"); 119 | log += ip; 120 | addLog(LOG_LEVEL_INFO, log); 121 | WiFi.config(ip, gw, subnet); 122 | } 123 | } 124 | else 125 | { 126 | log = F("WIFI : No SSID!"); 127 | addLog(LOG_LEVEL_INFO, log); 128 | NC_Count = 1; 129 | WifiAPMode(true); 130 | } 131 | } 132 | 133 | if (WiFi.status() == WL_CONNECTED) 134 | return true; 135 | 136 | return false; 137 | } 138 | 139 | 140 | //******************************************************************************** 141 | // Disconnect from Wifi AP 142 | //******************************************************************************** 143 | boolean WifiDisconnect() 144 | { 145 | WiFi.disconnect(); 146 | } 147 | 148 | 149 | //******************************************************************************** 150 | // Scan all Wifi Access Points 151 | //******************************************************************************** 152 | void WifiScan() 153 | { 154 | // Direct Serial is allowed here, since this function will only be called from serial input. 155 | Serial.println(F("WIFI : SSID Scan start")); 156 | int n = WiFi.scanNetworks(); 157 | if (n == 0) 158 | Serial.println(F("WIFI : No networks found")); 159 | else 160 | { 161 | Serial.print(F("WIFI : ")); 162 | Serial.print(n); 163 | Serial.println(F(" networks found")); 164 | for (int i = 0; i < n; ++i) 165 | { 166 | // Print SSID and RSSI for each network found 167 | Serial.print(F("WIFI : ")); 168 | Serial.print(i + 1); 169 | Serial.print(": "); 170 | Serial.print(WiFi.SSID(i)); 171 | Serial.print(" ("); 172 | Serial.print(WiFi.RSSI(i)); 173 | Serial.print(")"); 174 | Serial.println(""); 175 | delay(10); 176 | } 177 | } 178 | Serial.println(""); 179 | } 180 | 181 | 182 | //******************************************************************************** 183 | // Check if we are still connected to a Wifi AP 184 | //******************************************************************************** 185 | void WifiCheck() 186 | { 187 | 188 | if(wifiSetup) 189 | return; 190 | 191 | String log = ""; 192 | 193 | if (WiFi.status() != WL_CONNECTED) 194 | { 195 | NC_Count++; 196 | if (NC_Count > 2) 197 | { 198 | if (!WifiConnect(true,2)) 199 | WifiConnect(false,2); 200 | 201 | C_Count=0; 202 | if (WiFi.status() != WL_CONNECTED) 203 | WifiAPMode(true); 204 | NC_Count = 0; 205 | } 206 | } 207 | else 208 | { 209 | C_Count++; 210 | NC_Count = 0; 211 | if (C_Count > 2) // close AP after timeout if a Wifi connection is established... 212 | { 213 | byte wifimode = wifi_get_opmode(); 214 | if (wifimode == 2 || wifimode == 3) //apmode is active 215 | { 216 | WifiAPMode(false); 217 | log = F("WIFI : AP Mode inactive"); 218 | addLog(LOG_LEVEL_INFO, log); 219 | } 220 | } 221 | } 222 | } 223 | 224 | -------------------------------------------------------------------------------- /_C001_Domoticz_HTTP.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 | Protocol[protocolCount].usesID = true; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_001); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_SEND: 33 | { 34 | if (event->idx != 0) 35 | { 36 | ControllerSettingsStruct ControllerSettings; 37 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 38 | 39 | String authHeader = ""; 40 | if ((SecuritySettings.ControllerUser[event->ProtocolIndex][0] != 0) && (SecuritySettings.ControllerPassword[event->ProtocolIndex][0] != 0)) 41 | { 42 | base64 encoder; 43 | String auth = SecuritySettings.ControllerUser[event->ControllerIndex]; 44 | auth += ":"; 45 | auth += SecuritySettings.ControllerPassword[event->ControllerIndex]; 46 | authHeader = F("Authorization: Basic "); 47 | authHeader += encoder.encode(auth); 48 | authHeader += F(" \r\n"); 49 | } 50 | 51 | char log[80]; 52 | boolean success = false; 53 | char host[20]; 54 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 55 | 56 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, ControllerSettings.Port); 57 | addLog(LOG_LEVEL_DEBUG, log); 58 | 59 | // Use WiFiClient class to create TCP connections 60 | WiFiClient client; 61 | if (!client.connect(host, ControllerSettings.Port)) 62 | { 63 | connectionFailures++; 64 | strcpy_P(log, PSTR("HTTP : connection failed")); 65 | addLog(LOG_LEVEL_ERROR, log); 66 | return false; 67 | } 68 | statusLED(true); 69 | if (connectionFailures) 70 | connectionFailures--; 71 | 72 | // We now create a URI for the request 73 | String url = F("/json.htm?type=command¶m=udevice&idx="); 74 | url += event->idx; 75 | 76 | switch (event->sensorType) 77 | { 78 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 79 | url += F("&svalue="); 80 | url += toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]); 81 | break; 82 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 83 | url += F("&svalue="); 84 | url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 85 | break; 86 | case SENSOR_TYPE_DUAL: // any sensor that uses two simple values 87 | url += F("&svalue="); 88 | url += toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]); 89 | url += ";"; 90 | url += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]); 91 | break; 92 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 93 | url += F("&svalue="); 94 | url += toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]); 95 | url += ";"; 96 | url += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]); 97 | url += ";0"; 98 | break; 99 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 100 | url += F("&svalue="); 101 | url += toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]); 102 | url += ";0;0;"; 103 | url += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]); 104 | url += ";0"; 105 | break; 106 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 107 | url += F("&svalue="); 108 | url += toString(UserVar[event->BaseVarIndex], ExtraTaskSettings.TaskDeviceValueDecimals[0]); 109 | url += ";"; 110 | url += toString(UserVar[event->BaseVarIndex + 1], ExtraTaskSettings.TaskDeviceValueDecimals[1]); 111 | url += ";0;"; 112 | url += toString(UserVar[event->BaseVarIndex + 2], ExtraTaskSettings.TaskDeviceValueDecimals[2]); 113 | url += ";0"; 114 | break; 115 | case SENSOR_TYPE_SWITCH: 116 | url = F("/json.htm?type=command¶m=switchlight&idx="); 117 | url += event->idx; 118 | url += F("&switchcmd="); 119 | if (UserVar[event->BaseVarIndex] == 0) 120 | url += F("Off"); 121 | else 122 | url += F("On"); 123 | break; 124 | case SENSOR_TYPE_DIMMER: 125 | url = F("/json.htm?type=command¶m=switchlight&idx="); 126 | url += event->idx; 127 | url += F("&switchcmd="); 128 | if (UserVar[event->BaseVarIndex] == 0) 129 | url += F("Off"); 130 | else 131 | { 132 | url += F("Set%20Level&level="); 133 | url += UserVar[event->BaseVarIndex]; 134 | } 135 | break; 136 | } 137 | 138 | url.toCharArray(log, 80); 139 | addLog(LOG_LEVEL_DEBUG_MORE, log); 140 | 141 | // This will send the request to the server 142 | String request = F("GET "); 143 | request += url; 144 | request += F(" HTTP/1.1\r\n"); 145 | request += F("Host: "); 146 | request += host; 147 | request += F("\r\n"); 148 | request += authHeader; 149 | request += F("Connection: close\r\n\r\n"); 150 | client.print(request); 151 | 152 | unsigned long timer = millis() + 200; 153 | while (!client.available() && millis() < timer) 154 | delay(1); 155 | 156 | // Read all the lines of the reply from server and print them to Serial 157 | while (client.available()) { 158 | String line = client.readStringUntil('\n'); 159 | line.toCharArray(log, 80); 160 | addLog(LOG_LEVEL_DEBUG_MORE, log); 161 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 162 | { 163 | strcpy_P(log, PSTR("HTTP : Success")); 164 | addLog(LOG_LEVEL_DEBUG, log); 165 | success = true; 166 | } 167 | delay(1); 168 | } 169 | strcpy_P(log, PSTR("HTTP : closing connection")); 170 | addLog(LOG_LEVEL_DEBUG, log); 171 | 172 | client.flush(); 173 | client.stop(); 174 | } // if ixd !=0 175 | else 176 | { 177 | String log = F("HTTP : IDX cannot be zero!"); 178 | addLog(LOG_LEVEL_ERROR, log); 179 | } 180 | break; 181 | } 182 | } 183 | return success; 184 | } 185 | 186 | /* 187 | boolean Domoticz_getData(int idx, float *data, byte index) // todo 188 | { 189 | boolean success = false; 190 | char host[20]; 191 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[index][0], Settings.Controller_IP[index][1], Settings.Controller_IP[index][2], Settings.Controller_IP[index][3]); 192 | 193 | // Use WiFiClient class to create TCP connections 194 | WiFiClient client; 195 | if (!client.connect(host, Settings.ControllerPort[index])) 196 | { 197 | connectionFailures++; 198 | return false; 199 | } 200 | if (connectionFailures) 201 | connectionFailures--; 202 | 203 | // We now create a URI for the request 204 | String url = F("/json.htm?type=devices&rid="); 205 | url += idx; 206 | 207 | // This will send the request to the server 208 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 209 | "Host: " + host + "\r\n" + 210 | "Connection: close\r\n\r\n"); 211 | 212 | unsigned long timer = millis() + 200; 213 | while (!client.available() && millis() < timer) 214 | delay(1); 215 | 216 | // Read all the lines of the reply from server and print them to Serial 217 | 218 | while (client.available()) { 219 | String line = client.readStringUntil('\n'); 220 | if (line.substring(10, 14) == "Data") 221 | { 222 | String strValue = line.substring(19); 223 | byte pos = strValue.indexOf(' '); 224 | strValue = strValue.substring(0, pos); 225 | strValue.trim(); 226 | float value = strValue.toFloat(); 227 | data = value; 228 | success = true; 229 | } 230 | } 231 | return success; 232 | } 233 | 234 | */ 235 | 236 | -------------------------------------------------------------------------------- /_C003_Nodo_Telnet.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 003: Nodo Telnet ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_003 6 | #define CPLUGIN_ID_003 3 7 | #define CPLUGIN_NAME_003 "Nodo Telnet" 8 | 9 | boolean CPlugin_003(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_003; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 23; 22 | Protocol[protocolCount].usesID = true; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_003); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_SEND: 33 | { 34 | ControllerSettingsStruct ControllerSettings; 35 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 36 | 37 | char log[80]; 38 | boolean success = false; 39 | char host[20]; 40 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 41 | 42 | sprintf_P(log, PSTR("%s%s using port %u"), "TELNT: connecting to ", host,ControllerSettings.Port); 43 | addLog(LOG_LEVEL_DEBUG, log); 44 | 45 | // Use WiFiClient class to create TCP connections 46 | WiFiClient client; 47 | if (!client.connect(host, ControllerSettings.Port)) 48 | { 49 | connectionFailures++; 50 | strcpy_P(log, PSTR("TELNT: connection failed")); 51 | addLog(LOG_LEVEL_ERROR, log); 52 | return false; 53 | } 54 | statusLED(true); 55 | if (connectionFailures) 56 | connectionFailures--; 57 | 58 | // We now create a URI for the request 59 | String url = F("variableset "); 60 | url += event->idx; 61 | url += ","; 62 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 63 | url += "\n"; 64 | 65 | strcpy_P(log, PSTR("TELNT: Sending enter")); 66 | addLog(LOG_LEVEL_ERROR, log); 67 | client.print(" \n"); 68 | 69 | unsigned long timer = millis() + 200; 70 | while (!client.available() && millis() < timer) 71 | delay(1); 72 | 73 | timer = millis() + 1000; 74 | while (client.available() && millis() < timer && !success) 75 | { 76 | String line = client.readStringUntil('\n'); 77 | if (line.substring(0, 20) == "Enter your password:") 78 | { 79 | success = true; 80 | strcpy_P(log, PSTR("TELNT: Password request ok")); 81 | addLog(LOG_LEVEL_ERROR, log); 82 | } 83 | delay(1); 84 | } 85 | 86 | strcpy_P(log, PSTR("TELNT: Sending pw")); 87 | addLog(LOG_LEVEL_ERROR, log); 88 | client.println(SecuritySettings.ControllerPassword[event->ControllerIndex]); 89 | delay(100); 90 | while (client.available()) 91 | client.read(); 92 | 93 | strcpy_P(log, PSTR("TELNT: Sending cmd")); 94 | addLog(LOG_LEVEL_ERROR, log); 95 | client.print(url); 96 | delay(10); 97 | while (client.available()) 98 | client.read(); 99 | 100 | strcpy_P(log, PSTR("TELNT: closing connection")); 101 | addLog(LOG_LEVEL_DEBUG, log); 102 | 103 | client.stop(); 104 | 105 | break; 106 | } 107 | 108 | } 109 | return success; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /_C004_ThingSpeak.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 004: ThingSpeak ######################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_004 6 | #define CPLUGIN_ID_004 4 7 | #define CPLUGIN_NAME_004 "ThingSpeak" 8 | 9 | boolean CPlugin_004(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_004; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 80; 22 | Protocol[protocolCount].usesID = true; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_004); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_SEND: 33 | { 34 | ControllerSettingsStruct ControllerSettings; 35 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 36 | 37 | char log[80]; 38 | boolean success = false; 39 | char host[20]; 40 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 41 | 42 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,ControllerSettings.Port); 43 | addLog(LOG_LEVEL_DEBUG, log); 44 | 45 | // Use WiFiClient class to create TCP connections 46 | WiFiClient client; 47 | if (!client.connect(host, ControllerSettings.Port)) 48 | { 49 | connectionFailures++; 50 | strcpy_P(log, PSTR("HTTP : connection failed")); 51 | addLog(LOG_LEVEL_ERROR, log); 52 | return false; 53 | } 54 | statusLED(true); 55 | if (connectionFailures) 56 | connectionFailures--; 57 | 58 | String postDataStr = F("api_key="); 59 | postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // used for API key 60 | 61 | byte valueCount = getValueCountFromSensorType(event->sensorType); 62 | for (byte x = 0; x < valueCount; x++) 63 | { 64 | postDataStr += F("&field"); 65 | postDataStr += event->idx + x; 66 | postDataStr += "="; 67 | postDataStr += toString(UserVar[event->BaseVarIndex + x],ExtraTaskSettings.TaskDeviceValueDecimals[x]); 68 | } 69 | String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers. 70 | if (ControllerSettings.UseDNS) 71 | hostName = ControllerSettings.HostName; 72 | 73 | String postStr = F("POST /update HTTP/1.1\r\n"); 74 | postStr += F("Host: "); 75 | postStr += hostName; 76 | postStr += F("\r\n"); 77 | postStr += F("Connection: close\r\n"); 78 | 79 | postStr += F("Content-Type: application/x-www-form-urlencoded\r\n"); 80 | postStr += F("Content-Length: "); 81 | postStr += postDataStr.length(); 82 | postStr += F("\r\n\r\n"); 83 | postStr += postDataStr; 84 | 85 | // This will send the request to the server 86 | client.print(postStr); 87 | 88 | unsigned long timer = millis() + 200; 89 | while (!client.available() && millis() < timer) 90 | delay(1); 91 | 92 | // Read all the lines of the reply from server and print them to Serial 93 | while (client.available()) { 94 | String line = client.readStringUntil('\n'); 95 | line.toCharArray(log, 80); 96 | addLog(LOG_LEVEL_DEBUG_MORE, log); 97 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 98 | { 99 | strcpy_P(log, PSTR("HTTP : Succes!")); 100 | addLog(LOG_LEVEL_DEBUG, log); 101 | success = true; 102 | } 103 | delay(1); 104 | } 105 | strcpy_P(log, PSTR("HTTP : closing connection")); 106 | addLog(LOG_LEVEL_DEBUG, log); 107 | 108 | client.flush(); 109 | client.stop(); 110 | break; 111 | } 112 | 113 | } 114 | return success; 115 | } 116 | 117 | -------------------------------------------------------------------------------- /_C005_MQTT.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 | Protocol[protocolCount].usesID = false; 24 | break; 25 | } 26 | 27 | case CPLUGIN_GET_DEVICENAME: 28 | { 29 | string = F(CPLUGIN_NAME_005); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_TEMPLATE: 34 | { 35 | event->String1 = F("/%sysname%/#"); 36 | event->String2 = F("/%sysname%/%tskname%/%valname%"); 37 | break; 38 | } 39 | 40 | case CPLUGIN_PROTOCOL_RECV: 41 | { 42 | // Split topic into array 43 | String tmpTopic = event->String1.substring(1); 44 | String topicSplit[10]; 45 | int SlashIndex = tmpTopic.indexOf('/'); 46 | byte count = 0; 47 | while (SlashIndex > 0 && count < 10 - 1) 48 | { 49 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 50 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 51 | SlashIndex = tmpTopic.indexOf('/'); 52 | count++; 53 | } 54 | topicSplit[count] = tmpTopic; 55 | 56 | String cmd = ""; 57 | struct EventStruct TempEvent; 58 | 59 | if (topicSplit[count] == "cmd") 60 | { 61 | cmd = event->String2; 62 | parseCommandString(&TempEvent, cmd); 63 | TempEvent.Source = VALUE_SOURCE_MQTT; 64 | } 65 | else 66 | { 67 | cmd = topicSplit[count - 1]; 68 | TempEvent.Par1 = topicSplit[count].toInt(); 69 | TempEvent.Par2 = event->String2.toFloat(); 70 | TempEvent.Par3 = 0; 71 | } 72 | // in case of event, store to buffer and return... 73 | String command = parseString(cmd, 1); 74 | if (command == F("event")) 75 | eventBuffer = cmd.substring(6); 76 | else if 77 | (PluginCall(PLUGIN_WRITE, &TempEvent, cmd)); 78 | else 79 | remoteConfig(&TempEvent, cmd); 80 | 81 | break; 82 | } 83 | 84 | case CPLUGIN_PROTOCOL_SEND: 85 | { 86 | ControllerSettingsStruct ControllerSettings; 87 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 88 | 89 | statusLED(true); 90 | 91 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 92 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 93 | 94 | String pubname = ControllerSettings.Publish; 95 | pubname.replace(F("%sysname%"), Settings.Name); 96 | pubname.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName); 97 | pubname.replace(F("%id%"), String(event->idx)); 98 | 99 | String value = ""; 100 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 101 | byte valueCount = getValueCountFromSensorType(event->sensorType); 102 | for (byte x = 0; x < valueCount; x++) 103 | { 104 | String tmppubname = pubname; 105 | tmppubname.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[x]); 106 | if (event->sensorType == SENSOR_TYPE_LONG) 107 | value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 108 | else 109 | value = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 110 | MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag); 111 | String log = F("MQTT : "); 112 | log += tmppubname; 113 | log += " "; 114 | log += value; 115 | addLog(LOG_LEVEL_DEBUG, log); 116 | } 117 | break; 118 | } 119 | return success; 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /_C006_PiDome.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 006: PiDome MQTT ######################################## 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_006 6 | #define CPLUGIN_ID_006 6 7 | #define CPLUGIN_NAME_006 "PiDome MQTT" 8 | 9 | boolean CPlugin_006(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_006; 18 | Protocol[protocolCount].usesMQTT = true; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | Protocol[protocolCount].usesID = false; 24 | break; 25 | } 26 | 27 | case CPLUGIN_GET_DEVICENAME: 28 | { 29 | string = F(CPLUGIN_NAME_006); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_TEMPLATE: 34 | { 35 | event->String1 = F("/Home/#"); 36 | event->String2 = F("/hooks/devices/%id%/SensorData/%valname%"); 37 | break; 38 | } 39 | 40 | case CPLUGIN_PROTOCOL_RECV: 41 | { 42 | // topic structure /Home/Floor/Location/device//gpio/16 43 | // Split topic into array 44 | String tmpTopic = event->String1.substring(1); 45 | String topicSplit[10]; 46 | int SlashIndex = tmpTopic.indexOf('/'); 47 | byte count = 0; 48 | while (SlashIndex > 0 && count < 10 - 1) 49 | { 50 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 51 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 52 | SlashIndex = tmpTopic.indexOf('/'); 53 | count++; 54 | } 55 | topicSplit[count] = tmpTopic; 56 | 57 | String name = topicSplit[4]; 58 | String cmd = topicSplit[5]; 59 | struct EventStruct TempEvent; 60 | TempEvent.Par1 = topicSplit[6].toInt(); 61 | TempEvent.Par2 = 0; 62 | TempEvent.Par3 = 0; 63 | if (event->String2 == "false" || event->String2 == "true") 64 | { 65 | if (event->String2 == "true") 66 | TempEvent.Par2 = 1; 67 | } 68 | else 69 | TempEvent.Par2 = event->String2.toFloat(); 70 | if (name == Settings.Name) 71 | { 72 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 73 | } 74 | break; 75 | } 76 | 77 | case CPLUGIN_PROTOCOL_SEND: 78 | { 79 | ControllerSettingsStruct ControllerSettings; 80 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 81 | 82 | statusLED(true); 83 | 84 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 85 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 86 | 87 | String pubname = ControllerSettings.Publish; 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 | -------------------------------------------------------------------------------- /_C007_EmonCMS.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 007: Emoncms ############################################ 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_007 6 | #define CPLUGIN_ID_007 7 7 | #define CPLUGIN_NAME_007 "Emoncms" 8 | 9 | boolean CPlugin_007(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_007; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 80; 22 | Protocol[protocolCount].usesID = true; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_007); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_SEND: 33 | { 34 | ControllerSettingsStruct ControllerSettings; 35 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 36 | 37 | char log[80]; 38 | boolean success = false; 39 | char host[20]; 40 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 41 | 42 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,ControllerSettings.Port); 43 | addLog(LOG_LEVEL_DEBUG, log); 44 | 45 | // Use WiFiClient class to create TCP connections 46 | WiFiClient client; 47 | if (!client.connect(host, ControllerSettings.Port)) 48 | { 49 | connectionFailures++; 50 | strcpy_P(log, PSTR("HTTP : connection failed")); 51 | addLog(LOG_LEVEL_ERROR, log); 52 | return false; 53 | } 54 | statusLED(true); 55 | if (connectionFailures) 56 | connectionFailures--; 57 | 58 | String postDataStr = F("GET /emoncms/input/post.json?node="); 59 | 60 | postDataStr += Settings.Unit; 61 | postDataStr += F("&json="); 62 | 63 | switch (event->sensorType) 64 | { 65 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 66 | postDataStr += F("{field"); 67 | postDataStr += event->idx; 68 | postDataStr += ":"; 69 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 70 | postDataStr += "}"; 71 | break; 72 | case SENSOR_TYPE_TEMP_HUM: // dual value 73 | case SENSOR_TYPE_TEMP_BARO: 74 | case SENSOR_TYPE_DUAL: 75 | postDataStr += F("{field"); 76 | postDataStr += event->idx; 77 | postDataStr += ":"; 78 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 79 | postDataStr += F(",field"); 80 | postDataStr += event->idx + 1; 81 | postDataStr += ":"; 82 | postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 83 | postDataStr += "}"; 84 | break; 85 | case SENSOR_TYPE_TEMP_HUM_BARO: 86 | case SENSOR_TYPE_TRIPLE: 87 | postDataStr += F("{field"); 88 | postDataStr += event->idx; 89 | postDataStr += ":"; 90 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 91 | postDataStr += F(",field"); 92 | postDataStr += event->idx + 1; 93 | postDataStr += ":"; 94 | postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 95 | postDataStr += F(",field"); 96 | postDataStr += event->idx + 2; 97 | postDataStr += ":"; 98 | postDataStr += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 99 | postDataStr += "}"; 100 | break; 101 | case SENSOR_TYPE_SWITCH: 102 | break; 103 | } 104 | postDataStr += F("&apikey="); 105 | postDataStr += SecuritySettings.ControllerPassword[event->ControllerIndex]; // "0UDNN17RW6XAS2E5" // api key 106 | 107 | String hostName = host; 108 | if (ControllerSettings.UseDNS) 109 | hostName = ControllerSettings.HostName; 110 | 111 | String postStr = F(" HTTP/1.1\r\n"); 112 | postStr += F("Host: "); 113 | postStr += hostName; 114 | postStr += F("\r\n"); 115 | postStr += F("Connection: close\r\n"); 116 | postStr += F("\r\n"); 117 | 118 | postDataStr += postStr; 119 | 120 | if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) 121 | Serial.println(postDataStr); 122 | 123 | // This will send the request to the server 124 | client.print(postDataStr); 125 | 126 | unsigned long timer = millis() + 200; 127 | while (!client.available() && millis() < timer) 128 | delay(1); 129 | 130 | // Read all the lines of the reply from server and print them to Serial 131 | while (client.available()) { 132 | String line = client.readStringUntil('\n'); 133 | line.toCharArray(log, 80); 134 | addLog(LOG_LEVEL_DEBUG_MORE, log); 135 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 136 | { 137 | strcpy_P(log, PSTR("HTTP : Succes!")); 138 | addLog(LOG_LEVEL_DEBUG, log); 139 | success = true; 140 | } 141 | delay(1); 142 | } 143 | strcpy_P(log, PSTR("HTTP : closing connection")); 144 | addLog(LOG_LEVEL_DEBUG, log); 145 | 146 | client.flush(); 147 | client.stop(); 148 | break; 149 | } 150 | 151 | } 152 | return success; 153 | } 154 | 155 | -------------------------------------------------------------------------------- /_C008_HTTP.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 008: Generic HTTP ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_008 6 | #define CPLUGIN_ID_008 8 7 | #define CPLUGIN_NAME_008 "Generic HTTP" 8 | 9 | boolean CPlugin_008(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_008; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 80; 23 | Protocol[protocolCount].usesID = false; 24 | break; 25 | } 26 | 27 | case CPLUGIN_GET_DEVICENAME: 28 | { 29 | string = F(CPLUGIN_NAME_008); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_TEMPLATE: 34 | { 35 | event->String1 = ""; 36 | event->String2 = F("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%"); 37 | break; 38 | } 39 | 40 | case CPLUGIN_PROTOCOL_SEND: 41 | { 42 | byte valueCount = getValueCountFromSensorType(event->sensorType); 43 | for (byte x = 0; x < valueCount; x++) 44 | { 45 | if (event->sensorType == SENSOR_TYPE_LONG) 46 | HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 47 | else 48 | HTTPSend(event, x, UserVar[event->BaseVarIndex + x], 0); 49 | if (valueCount > 1) 50 | { 51 | unsigned long timer = millis() + Settings.MessageDelay; 52 | while (millis() < timer) 53 | backgroundtasks(); 54 | } 55 | } 56 | break; 57 | } 58 | 59 | } 60 | return success; 61 | } 62 | 63 | 64 | //******************************************************************************** 65 | // Generic HTTP get request 66 | //******************************************************************************** 67 | boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 68 | { 69 | ControllerSettingsStruct ControllerSettings; 70 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 71 | 72 | String authHeader = ""; 73 | if ((SecuritySettings.ControllerUser[event->ControllerIndex][0] != 0) && (SecuritySettings.ControllerPassword[event->ControllerIndex][0] != 0)) 74 | { 75 | base64 encoder; 76 | String auth = SecuritySettings.ControllerUser[event->ControllerIndex]; 77 | auth += ":"; 78 | auth += SecuritySettings.ControllerPassword[event->ControllerIndex]; 79 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 80 | } 81 | 82 | char log[80]; 83 | boolean success = false; 84 | char host[20]; 85 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 86 | 87 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, ControllerSettings.Port); 88 | addLog(LOG_LEVEL_DEBUG, log); 89 | 90 | // Use WiFiClient class to create TCP connections 91 | WiFiClient client; 92 | if (!client.connect(host, ControllerSettings.Port)) 93 | { 94 | connectionFailures++; 95 | strcpy_P(log, PSTR("HTTP : connection failed")); 96 | addLog(LOG_LEVEL_ERROR, log); 97 | return false; 98 | } 99 | statusLED(true); 100 | if (connectionFailures) 101 | connectionFailures--; 102 | 103 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 104 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 105 | 106 | String url = "/"; 107 | url += ControllerSettings.Publish; 108 | url.replace(F("%sysname%"), URLEncode(Settings.Name)); 109 | url.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName)); 110 | url.replace(F("%id%"), String(event->idx)); 111 | url.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex])); 112 | if (longValue) 113 | url.replace(F("%value%"), String(longValue)); 114 | else 115 | url.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex])); 116 | 117 | url.toCharArray(log, 80); 118 | addLog(LOG_LEVEL_DEBUG_MORE, log); 119 | 120 | String hostName = host; 121 | if (ControllerSettings.UseDNS) 122 | hostName = ControllerSettings.HostName; 123 | 124 | // This will send the request to the server 125 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 126 | "Host: " + hostName + "\r\n" + authHeader + 127 | "Connection: close\r\n\r\n"); 128 | 129 | unsigned long timer = millis() + 200; 130 | while (!client.available() && millis() < timer) 131 | delay(1); 132 | 133 | // Read all the lines of the reply from server and print them to Serial 134 | while (client.available()) { 135 | String line = client.readStringUntil('\n'); 136 | line.toCharArray(log, 80); 137 | addLog(LOG_LEVEL_DEBUG_MORE, log); 138 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 139 | { 140 | strcpy_P(log, PSTR("HTTP : Succes!")); 141 | addLog(LOG_LEVEL_DEBUG, log); 142 | success = true; 143 | } 144 | delay(1); 145 | } 146 | strcpy_P(log, PSTR("HTTP : closing connection")); 147 | addLog(LOG_LEVEL_DEBUG, log); 148 | 149 | client.flush(); 150 | client.stop(); 151 | } 152 | -------------------------------------------------------------------------------- /_C009_FHEM_HTTP.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 009: FHEM HTTP ########################################## 3 | //####################################################################################################### 4 | 5 | /******************************************************************************* 6 | * Modified version of "Domoticz HTTP CPLUGIN" 7 | * Copyright 2016 dev0 (https://forum.fhem.de/index.php?action=profile;u=7465) 8 | * Release notes: 9 | - v1.0 10 | - changed switch and dimmer setreading cmds 11 | - v1.01 12 | - added json content to http requests 13 | - v1.02 14 | - some optimizations as requested by mvdbro 15 | - fixed JSON TaskDeviceValueDecimals handling 16 | - ArduinoJson Library v5.6.4 required (as used by stable R120) 17 | - parse for HTTP errors 400, 401 18 | - moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module 19 | /******************************************************************************/ 20 | 21 | #define CPLUGIN_009 22 | #define CPLUGIN_ID_009 9 23 | #define CPLUGIN_NAME_009 "FHEM HTTP" 24 | 25 | boolean CPlugin_009(byte function, struct EventStruct *event, String& string) 26 | { 27 | boolean success = false; 28 | 29 | switch (function) 30 | { 31 | case CPLUGIN_PROTOCOL_ADD: 32 | { 33 | Protocol[++protocolCount].Number = CPLUGIN_ID_009; 34 | Protocol[protocolCount].usesMQTT = false; 35 | Protocol[protocolCount].usesTemplate = false; 36 | Protocol[protocolCount].usesAccount = true; 37 | Protocol[protocolCount].usesPassword = true; 38 | Protocol[protocolCount].defaultPort = 8383; 39 | break; 40 | } 41 | 42 | case CPLUGIN_GET_DEVICENAME: 43 | { 44 | string = F(CPLUGIN_NAME_009); 45 | break; 46 | } 47 | 48 | case CPLUGIN_PROTOCOL_SEND: 49 | { 50 | 51 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 52 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 53 | 54 | // We now create a URI for the request 55 | String url = F("/fhem?cmd="); 56 | 57 | // Create json root object 58 | DynamicJsonBuffer jsonBuffer; 59 | JsonObject& root = jsonBuffer.createObject(); 60 | root["module"] = "ESPEasy"; 61 | root["version"] = "1.02"; 62 | 63 | // Create nested objects 64 | JsonObject& data = root.createNestedObject("data"); 65 | JsonObject& ESP = data.createNestedObject("ESP"); 66 | ESP["name"] = Settings.Name; 67 | ESP["unit"] = Settings.Unit; 68 | ESP["version"] = Settings.Version; 69 | ESP["build"] = Settings.Build; 70 | ESP["sleep"] = Settings.deepSleep; 71 | 72 | // embed IP, important if there is NAT/PAT 73 | char ipStr[20]; 74 | IPAddress ip = WiFi.localIP(); 75 | sprintf_P(ipStr, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); 76 | ESP["ip"] = ipStr; 77 | 78 | // Create nested SENSOR json object 79 | JsonObject& SENSOR = data.createNestedObject("SENSOR"); 80 | byte valueCount = getValueCountFromSensorType(event->sensorType); 81 | char itemNames[valueCount][2]; 82 | for (byte x = 0; x < valueCount; x++) 83 | { 84 | String s; 85 | url += F("setreading%20"); 86 | url += Settings.Name; 87 | url += F("%20"); 88 | url += ExtraTaskSettings.TaskDeviceValueNames[x]; 89 | url += F("%20"); 90 | 91 | // Each sensor value get an own object (0..n) 92 | sprintf(itemNames[x],"%d",x); 93 | JsonObject& val = SENSOR.createNestedObject(itemNames[x]); 94 | val["deviceName"] = ExtraTaskSettings.TaskDeviceName; 95 | val["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[x]; 96 | val["type"] = event->sensorType; 97 | 98 | if (event->sensorType == SENSOR_TYPE_LONG) { 99 | s = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 100 | url += s; 101 | val["value"] = s; 102 | 103 | } else { // All other sensor types 104 | s = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 105 | url += s; 106 | val["value"] = s; 107 | } 108 | 109 | // Split FHEM commands by ";" 110 | if (x < valueCount-1) 111 | url += F("%3B"); 112 | } 113 | 114 | // Create json buffer 115 | char buffer[root.measureLength() +1]; 116 | root.printTo(buffer, sizeof(buffer)); 117 | // Push data to server 118 | FHEMHTTPsend(url, buffer, event->ControllerIndex); 119 | break; 120 | } 121 | } 122 | return success; 123 | } 124 | 125 | 126 | //******************************************************************************** 127 | // FHEM HTTP request 128 | //******************************************************************************** 129 | boolean FHEMHTTPsend(String url, char* buffer, byte index) 130 | { 131 | ControllerSettingsStruct ControllerSettings; 132 | LoadControllerSettings(index, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 133 | 134 | boolean success = false; 135 | 136 | String authHeader = ""; 137 | if ((SecuritySettings.ControllerUser[index][0] != 0) && (SecuritySettings.ControllerPassword[index][0] != 0)) { 138 | base64 encoder; 139 | String auth = SecuritySettings.ControllerUser[index]; 140 | auth += ":"; 141 | auth += SecuritySettings.ControllerPassword[index]; 142 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 143 | } 144 | 145 | char log[80]; 146 | url.toCharArray(log, 80); 147 | addLog(LOG_LEVEL_DEBUG_MORE, log); 148 | 149 | char host[20]; 150 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 151 | 152 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,ControllerSettings.Port); 153 | addLog(LOG_LEVEL_DEBUG, log); 154 | 155 | // Use WiFiClient class to create TCP connections 156 | WiFiClient client; 157 | if (!client.connect(host, ControllerSettings.Port)) { 158 | connectionFailures++; 159 | strcpy_P(log, PSTR("HTTP : connection failed")); 160 | addLog(LOG_LEVEL_ERROR, log); 161 | return false; 162 | } 163 | 164 | statusLED(true); 165 | if (connectionFailures) 166 | connectionFailures--; 167 | 168 | // This will send the request to the server 169 | int len = strlen(buffer); 170 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 171 | "Content-Length: "+ len + "\r\n" + 172 | "Host: " + host + "\r\n" + authHeader + 173 | "Connection: close\r\n\r\n" 174 | + buffer); 175 | 176 | unsigned long timer = millis() + 200; 177 | while (!client.available() && millis() < timer) 178 | delay(1); 179 | 180 | // Read all the lines of the reply from server and print them to Serial 181 | while (client.available()) { 182 | String line = client.readStringUntil('\n'); 183 | String helper = line; 184 | line.toCharArray(log, 80); 185 | addLog(LOG_LEVEL_DEBUG_MORE, log); 186 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) { 187 | strcpy_P(log, PSTR("HTTP : Success")); 188 | success = true; 189 | } 190 | else if (line.substring(0, 24) == F("HTTP/1.1 400 Bad Request")) { 191 | strcpy_P(log, PSTR("HTTP : Unauthorized")); 192 | } 193 | else if (line.substring(0, 25) == F("HTTP/1.1 401 Unauthorized")) { 194 | strcpy_P(log, PSTR("HTTP : Unauthorized")); 195 | } 196 | addLog(LOG_LEVEL_DEBUG, log); 197 | delay(1); 198 | } 199 | strcpy_P(log, PSTR("HTTP : closing connection")); 200 | addLog(LOG_LEVEL_DEBUG, log); 201 | client.flush(); 202 | client.stop(); 203 | } 204 | -------------------------------------------------------------------------------- /_C010_UDP.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 010: Generic UDP ######################################## 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_010 6 | #define CPLUGIN_ID_010 10 7 | #define CPLUGIN_NAME_010 "Generic UDP" 8 | 9 | boolean CPlugin_010(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_010; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 514; 23 | Protocol[protocolCount].usesID = false; 24 | break; 25 | } 26 | 27 | case CPLUGIN_GET_DEVICENAME: 28 | { 29 | string = F(CPLUGIN_NAME_010); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_TEMPLATE: 34 | { 35 | event->String1 = ""; 36 | event->String2 = F("%sysname%_%tskname%_%valname%=%value%"); 37 | break; 38 | } 39 | 40 | case CPLUGIN_PROTOCOL_SEND: 41 | { 42 | byte valueCount = getValueCountFromSensorType(event->sensorType); 43 | for (byte x = 0; x < valueCount; x++) 44 | { 45 | if (event->sensorType == SENSOR_TYPE_LONG) 46 | C010_Send(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 47 | else 48 | C010_Send(event, x, UserVar[event->BaseVarIndex + x], 0); 49 | if (valueCount > 1) 50 | { 51 | unsigned long timer = millis() + Settings.MessageDelay; 52 | while (millis() < timer) 53 | backgroundtasks(); 54 | } 55 | } 56 | break; 57 | } 58 | 59 | } 60 | return success; 61 | } 62 | 63 | 64 | //******************************************************************************** 65 | // Generic UDP message 66 | //******************************************************************************** 67 | boolean C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 68 | { 69 | ControllerSettingsStruct ControllerSettings; 70 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 71 | 72 | char log[80]; 73 | boolean success = false; 74 | char host[20]; 75 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 76 | 77 | sprintf_P(log, PSTR("%s%s using port %u"), "UDP : sending to ", host, ControllerSettings.Port); 78 | addLog(LOG_LEVEL_DEBUG, log); 79 | 80 | statusLED(true); 81 | 82 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 83 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 84 | 85 | String msg = ""; 86 | msg += ControllerSettings.Publish; 87 | msg.replace(F("%sysname%"), Settings.Name); 88 | msg.replace(F("%tskname%"), ExtraTaskSettings.TaskDeviceName); 89 | msg.replace(F("%id%"), String(event->idx)); 90 | msg.replace(F("%valname%"), ExtraTaskSettings.TaskDeviceValueNames[varIndex]); 91 | if (longValue) 92 | msg.replace(F("%value%"), String(longValue)); 93 | else 94 | msg.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex])); 95 | 96 | IPAddress IP(ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 97 | portUDP.beginPacket(IP, ControllerSettings.Port); 98 | portUDP.write(msg.c_str()); 99 | portUDP.endPacket(); 100 | 101 | msg.toCharArray(log, 80); 102 | addLog(LOG_LEVEL_DEBUG_MORE, log); 103 | 104 | } 105 | 106 | -------------------------------------------------------------------------------- /_C011_HTTP_Adv.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 011: Generic HTTP ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_011 6 | #define CPLUGIN_ID_011 11 7 | #define CPLUGIN_NAME_011 "Generic HTTP Advanced" 8 | 9 | #define P011_HTTP_METHOD_MAX_LEN 16 10 | #define P011_HTTP_URI_MAX_LEN 240 11 | #define P011_HTTP_HEADER_MAX_LEN 256 12 | #define P011_HTTP_BODY_MAX_LEN 512 13 | 14 | struct P011_ConfigStruct 15 | { 16 | char HttpMethod[P011_HTTP_METHOD_MAX_LEN]; 17 | char HttpUri[P011_HTTP_URI_MAX_LEN]; 18 | char HttpHeader[P011_HTTP_HEADER_MAX_LEN]; 19 | char HttpBody[P011_HTTP_BODY_MAX_LEN]; 20 | }; 21 | 22 | boolean CPlugin_011(byte function, struct EventStruct *event, String& string) 23 | { 24 | boolean success = false; 25 | 26 | switch (function) 27 | { 28 | case CPLUGIN_PROTOCOL_ADD: 29 | { 30 | Protocol[++protocolCount].Number = CPLUGIN_ID_011; 31 | Protocol[protocolCount].usesMQTT = false; 32 | Protocol[protocolCount].usesAccount = false; 33 | Protocol[protocolCount].usesPassword = false; 34 | Protocol[protocolCount].defaultPort = 80; 35 | Protocol[protocolCount].usesID = false; 36 | break; 37 | } 38 | 39 | case CPLUGIN_GET_DEVICENAME: 40 | { 41 | string = F(CPLUGIN_NAME_011); 42 | break; 43 | } 44 | 45 | case CPLUGIN_WEBFORM_LOAD: 46 | { 47 | P011_ConfigStruct customConfig; 48 | LoadCustomControllerSettings((byte*)&customConfig, sizeof(customConfig)); 49 | String methods[] = { F("GET"), F("POST"), F("PUT") }; 50 | string += F("HTTP Method :"); 61 | 62 | string += F("HTTP URI:"); 67 | 68 | string += F("HTTP Header:"); 73 | 74 | string += F("HTTP Body:"); 79 | break; 80 | } 81 | 82 | case CPLUGIN_WEBFORM_SAVE: 83 | { 84 | P011_ConfigStruct customConfig; 85 | String httpmethod = WebServer.arg(F("P011httpmethod")); 86 | String httpuri = WebServer.arg(F("P011httpuri")); 87 | String httpheader = WebServer.arg(F("P011httpheader")); 88 | String httpbody = WebServer.arg(F("P011httpbody")); 89 | strncpy(customConfig.HttpMethod, httpmethod.c_str(), sizeof(customConfig.HttpMethod)); 90 | strncpy(customConfig.HttpUri, httpuri.c_str(), sizeof(customConfig.HttpUri)); 91 | strncpy(customConfig.HttpHeader, httpheader.c_str(), sizeof(customConfig.HttpHeader)); 92 | strncpy(customConfig.HttpBody, httpbody.c_str(), sizeof(customConfig.HttpBody)); 93 | SaveCustomControllerSettings((byte*)&customConfig, sizeof(customConfig)); 94 | break; 95 | } 96 | 97 | case CPLUGIN_PROTOCOL_SEND: 98 | { 99 | switch (event->sensorType) 100 | { 101 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 102 | case SENSOR_TYPE_SWITCH: 103 | case SENSOR_TYPE_DIMMER: 104 | HTTPSend011(event, 0, UserVar[event->BaseVarIndex], 0); 105 | break; 106 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 107 | HTTPSend011(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 108 | break; 109 | case SENSOR_TYPE_TEMP_HUM: 110 | case SENSOR_TYPE_TEMP_BARO: 111 | { 112 | HTTPSend011(event, 0, UserVar[event->BaseVarIndex], 0); 113 | unsigned long timer = millis() + Settings.MessageDelay; 114 | while (millis() < timer) 115 | backgroundtasks(); 116 | HTTPSend011(event, 1, UserVar[event->BaseVarIndex + 1], 0); 117 | break; 118 | } 119 | case SENSOR_TYPE_TEMP_HUM_BARO: 120 | { 121 | HTTPSend011(event, 0, UserVar[event->BaseVarIndex], 0); 122 | unsigned long timer = millis() + Settings.MessageDelay; 123 | while (millis() < timer) 124 | backgroundtasks(); 125 | HTTPSend011(event, 1, UserVar[event->BaseVarIndex + 1], 0); 126 | timer = millis() + Settings.MessageDelay; 127 | while (millis() < timer) 128 | backgroundtasks(); 129 | HTTPSend011(event, 2, UserVar[event->BaseVarIndex + 2], 0); 130 | break; 131 | } 132 | } 133 | break; 134 | } 135 | 136 | } 137 | return success; 138 | } 139 | 140 | 141 | //******************************************************************************** 142 | // Generic HTTP get request 143 | //******************************************************************************** 144 | boolean HTTPSend011(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 145 | { 146 | ControllerSettingsStruct ControllerSettings; 147 | LoadControllerSettings(event->ControllerIndex, (byte*)&ControllerSettings, sizeof(ControllerSettings)); 148 | 149 | P011_ConfigStruct customConfig; 150 | LoadCustomControllerSettings((byte*)&customConfig, sizeof(customConfig)); 151 | 152 | char log[80]; 153 | boolean success = false; 154 | char host[20]; 155 | sprintf_P(host, PSTR("%u.%u.%u.%u"), ControllerSettings.IP[0], ControllerSettings.IP[1], ControllerSettings.IP[2], ControllerSettings.IP[3]); 156 | 157 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, ControllerSettings.Port); 158 | addLog(LOG_LEVEL_DEBUG, log); 159 | 160 | // Use WiFiClient class to create TCP connections 161 | WiFiClient client; 162 | if (!client.connect(host, ControllerSettings.Port)) 163 | { 164 | connectionFailures++; 165 | strcpy_P(log, PSTR("HTTP : connection failed")); 166 | addLog(LOG_LEVEL_ERROR, log); 167 | return false; 168 | } 169 | statusLED(true); 170 | if (connectionFailures) 171 | connectionFailures--; 172 | 173 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 174 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 175 | 176 | String hostName = host; 177 | if (ControllerSettings.UseDNS) 178 | hostName = ControllerSettings.HostName[event->ProtocolIndex]; 179 | 180 | String payload = String(customConfig.HttpMethod) + " /"; 181 | payload += customConfig.HttpUri; 182 | payload += F(" HTTP/1.1\r\n"); 183 | payload += F("Host: "); 184 | payload += hostName; 185 | payload += F("\r\nConnection: close\r\n\r\n"); 186 | 187 | if (strlen(customConfig.HttpHeader) > 0) 188 | payload += customConfig.HttpHeader; 189 | ReplaceTokenByValue(payload, event, varIndex, value, longValue); 190 | 191 | if (strlen(customConfig.HttpBody) > 0) 192 | { 193 | String body = String(customConfig.HttpBody); 194 | ReplaceTokenByValue(body, event, varIndex, value, longValue); 195 | payload += F("\r\nContent-Length: "); 196 | payload += String(body.length()); 197 | payload += F("\r\n\r\n"); 198 | payload += body; 199 | } 200 | 201 | // This will send the request to the server 202 | client.print(payload); 203 | 204 | unsigned long timer = millis() + 200; 205 | while (!client.available() && millis() < timer) 206 | delay(1); 207 | 208 | // Read all the lines of the reply from server and print them to Serial 209 | while (client.available()) { 210 | String line = client.readStringUntil('\n'); 211 | line.toCharArray(log, 80); 212 | addLog(LOG_LEVEL_DEBUG_MORE, log); 213 | if (line.substring(0, 15) == F("HTTP/1.1 200 OK")) 214 | { 215 | strcpy_P(log, PSTR("HTTP : Succes!")); 216 | addLog(LOG_LEVEL_DEBUG, log); 217 | success = true; 218 | } 219 | delay(1); 220 | } 221 | strcpy_P(log, PSTR("HTTP : closing connection")); 222 | addLog(LOG_LEVEL_DEBUG, log); 223 | 224 | client.flush(); 225 | client.stop(); 226 | } 227 | 228 | 229 | //******************************************************************************** 230 | // Replace the token in a string by real value. 231 | //******************************************************************************** 232 | void ReplaceTokenByValue(String& s, struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 233 | { 234 | s.replace(F("%sysname%"), URLEncode(Settings.Name)); 235 | s.replace(F("%tskname%"), URLEncode(ExtraTaskSettings.TaskDeviceName)); 236 | s.replace(F("%id%"), String(event->idx)); 237 | s.replace(F("%valname%"), URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex])); 238 | if (longValue) 239 | s.replace(F("%value%"), String(longValue)); 240 | else 241 | s.replace(F("%value%"), toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex])); 242 | } 243 | 244 | -------------------------------------------------------------------------------- /_N001_Email.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Notification Plugin 001: Email ############################################ 3 | //####################################################################################################### 4 | 5 | #define NPLUGIN_001 6 | #define NPLUGIN_ID_001 1 7 | #define NPLUGIN_NAME_001 "Email (SMTP)" 8 | 9 | #define NPLUGIN_001_TIMEOUT 3000 10 | 11 | boolean NPlugin_001(byte function, struct EventStruct *event, String& string) 12 | { 13 | boolean success = false; 14 | 15 | switch (function) 16 | { 17 | case NPLUGIN_PROTOCOL_ADD: 18 | { 19 | Notification[++notificationCount].Number = NPLUGIN_ID_001; 20 | Notification[notificationCount].usesMessaging = true; 21 | Notification[notificationCount].usesGPIO=0; 22 | break; 23 | } 24 | 25 | case NPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(NPLUGIN_NAME_001); 28 | break; 29 | } 30 | 31 | case NPLUGIN_WRITE: 32 | { 33 | String log = ""; 34 | String command = parseString(string, 1); 35 | 36 | if (command == F("email")) 37 | { 38 | NotificationSettingsStruct NotificationSettings; 39 | LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings)); 40 | NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, NotificationSettings.Subject, NotificationSettings.Body, NotificationSettings.Server, NotificationSettings.Port); 41 | success = true; 42 | } 43 | break; 44 | } 45 | 46 | case NPLUGIN_NOTIFY: 47 | { 48 | NotificationSettingsStruct NotificationSettings; 49 | LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings)); 50 | String subject = NotificationSettings.Subject; 51 | String body = ""; 52 | if (string.length() >0) 53 | body = string; 54 | else 55 | body = NotificationSettings.Body; 56 | subject = parseTemplate(subject, subject.length()); 57 | body = parseTemplate(body, body.length()); 58 | NPlugin_001_send(NotificationSettings.Domain, NotificationSettings.Receiver, NotificationSettings.Sender, subject, body, NotificationSettings.Server, NotificationSettings.Port); 59 | success = true; 60 | } 61 | 62 | } 63 | return success; 64 | } 65 | 66 | boolean NPlugin_001_send(String aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort) 67 | { 68 | boolean myStatus = false; 69 | 70 | // Use WiFiClient class to create TCP connections 71 | WiFiClient client; 72 | if (!client.connect(aHost.c_str(), aPort)) { 73 | myStatus = false; 74 | } 75 | else { 76 | 77 | // Wait for Client to Start Sending 78 | // The MTA Exchange 79 | while (true) { 80 | 81 | if (NPlugin_001_MTA(client, "", "220 ") == false) break; 82 | if (NPlugin_001_MTA(client, "EHLO " + aDomain, "250 ") == false) break; 83 | if (NPlugin_001_MTA(client, "MAIL FROM:" + aFrom + "", "250 ") == false) break; 84 | if (NPlugin_001_MTA(client, "RCPT TO:" + aTo + "", "250 ") == false) break; 85 | if (NPlugin_001_MTA(client, "DATA", "354 ") == false) break; 86 | if (NPlugin_001_MTA(client, "Subject:" + aSub + "\r\n\r\n" + aMesg + "\r\n.\r\n", "250 ") == false) break; 87 | 88 | myStatus = true; 89 | break; 90 | 91 | } 92 | 93 | client.flush(); 94 | client.stop(); 95 | 96 | if (myStatus == true) { 97 | String log = F("EMAIL: Connection Closed Successfully"); 98 | addLog(LOG_LEVEL_INFO, log); 99 | } 100 | else { 101 | String log = F("EMAIL: Connection Closed With Error"); 102 | addLog(LOG_LEVEL_ERROR, log); 103 | } 104 | 105 | } 106 | 107 | return myStatus; 108 | 109 | } 110 | 111 | 112 | boolean NPlugin_001_MTA(WiFiClient client, String aStr, String aWaitForPattern) 113 | { 114 | 115 | boolean myStatus = false; 116 | 117 | addLog(LOG_LEVEL_DEBUG, aStr); 118 | 119 | if (aStr.length() ) client.println(aStr); 120 | 121 | yield(); 122 | 123 | // Wait For Response 124 | unsigned long ts = millis(); 125 | while (true) { 126 | if ( ts + NPLUGIN_001_TIMEOUT < millis() ) { 127 | myStatus = false; 128 | break; 129 | } 130 | 131 | yield(); 132 | 133 | String line = client.readStringUntil('\n'); 134 | 135 | addLog(LOG_LEVEL_DEBUG, line); 136 | 137 | if (line.indexOf(aWaitForPattern) >= 0) { 138 | myStatus = true; 139 | break; 140 | } 141 | } 142 | 143 | return myStatus; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /_N002_Buzzer.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Notification Plugin 002: Buzzer ########################################### 3 | //####################################################################################################### 4 | 5 | #define NPLUGIN_002 6 | #define NPLUGIN_ID_002 2 7 | #define NPLUGIN_NAME_002 "Buzzer" 8 | 9 | boolean NPlugin_002(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case NPLUGIN_PROTOCOL_ADD: 16 | { 17 | Notification[++notificationCount].Number = NPLUGIN_ID_002; 18 | Notification[notificationCount].usesMessaging = false; 19 | Notification[notificationCount].usesGPIO=1; 20 | break; 21 | } 22 | 23 | case NPLUGIN_GET_DEVICENAME: 24 | { 25 | string = F(NPLUGIN_NAME_002); 26 | break; 27 | } 28 | 29 | case NPLUGIN_WRITE: 30 | { 31 | String log = ""; 32 | String command = parseString(string, 1); 33 | 34 | if (command == F("buzzer")) 35 | { 36 | NotificationSettingsStruct NotificationSettings; 37 | LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings)); 38 | success = true; 39 | } 40 | break; 41 | } 42 | 43 | case NPLUGIN_NOTIFY: 44 | { 45 | NotificationSettingsStruct NotificationSettings; 46 | LoadNotificationSettings(event->NotificationIndex, (byte*)&NotificationSettings, sizeof(NotificationSettings)); 47 | NPlugin_002_tone(NotificationSettings.Pin1, 500, 500); 48 | success = true; 49 | } 50 | 51 | } 52 | return success; 53 | } 54 | 55 | void NPlugin_002_tone(uint8_t _pin, unsigned int frequency, unsigned long duration) { 56 | 57 | analogWriteFreq(frequency); 58 | analogWrite(_pin,100); 59 | delay(duration); 60 | analogWrite(_pin,0); 61 | } 62 | 63 | -------------------------------------------------------------------------------- /_P002_ADC.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 002: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_002 6 | #define PLUGIN_ID_002 2 7 | #define PLUGIN_NAME_002 "Analog input" 8 | #define PLUGIN_VALUENAME1_002 "Analog" 9 | boolean Plugin_002(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_002; 19 | Device[deviceCount].Type = DEVICE_TYPE_ANALOG; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = true; 25 | Device[deviceCount].ValueCount = 1; 26 | Device[deviceCount].SendDataOption = true; 27 | Device[deviceCount].TimerOption = true; 28 | Device[deviceCount].GlobalSyncOption = true; 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_002); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002)); 41 | break; 42 | } 43 | 44 | case PLUGIN_READ: 45 | { 46 | int value = analogRead(A0); 47 | UserVar[event->BaseVarIndex] = (float)value; 48 | String log = F("ADC : Analog value: "); 49 | log += value; 50 | addLog(LOG_LEVEL_INFO,log); 51 | success = true; 52 | break; 53 | } 54 | } 55 | return success; 56 | } 57 | -------------------------------------------------------------------------------- /_P003_Pulse.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 003: Pulse ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_003 6 | #define PLUGIN_ID_003 3 7 | #define PLUGIN_NAME_003 "Pulse Counter" 8 | #define PLUGIN_VALUENAME1_003 "Count" 9 | #define PLUGIN_VALUENAME2_003 "Total" 10 | #define PLUGIN_VALUENAME3_003 "Time" 11 | 12 | void Plugin_003_pulse_interrupt1() ICACHE_RAM_ATTR; 13 | void Plugin_003_pulse_interrupt2() ICACHE_RAM_ATTR; 14 | void Plugin_003_pulse_interrupt3() ICACHE_RAM_ATTR; 15 | void Plugin_003_pulse_interrupt4() ICACHE_RAM_ATTR; 16 | void Plugin_003_pulse_interrupt5() ICACHE_RAM_ATTR; 17 | void Plugin_003_pulse_interrupt6() ICACHE_RAM_ATTR; 18 | void Plugin_003_pulse_interrupt7() ICACHE_RAM_ATTR; 19 | void Plugin_003_pulse_interrupt8() ICACHE_RAM_ATTR; 20 | 21 | unsigned long Plugin_003_pulseCounter[TASKS_MAX]; 22 | unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX]; 23 | unsigned long Plugin_003_pulseTime[TASKS_MAX]; 24 | unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX]; 25 | 26 | boolean Plugin_003(byte function, struct EventStruct *event, String& string) 27 | { 28 | boolean success = false; 29 | 30 | switch (function) 31 | { 32 | 33 | case PLUGIN_DEVICE_ADD: 34 | { 35 | Device[++deviceCount].Number = PLUGIN_ID_003; 36 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 37 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 38 | Device[deviceCount].Ports = 0; 39 | Device[deviceCount].PullUpOption = false; 40 | Device[deviceCount].InverseLogicOption = false; 41 | Device[deviceCount].FormulaOption = true; 42 | Device[deviceCount].ValueCount = 3; 43 | Device[deviceCount].SendDataOption = true; 44 | Device[deviceCount].TimerOption = true; 45 | Device[deviceCount].GlobalSyncOption = true; 46 | break; 47 | } 48 | 49 | case PLUGIN_GET_DEVICENAME: 50 | { 51 | string = F(PLUGIN_NAME_003); 52 | break; 53 | } 54 | 55 | case PLUGIN_GET_DEVICEVALUENAMES: 56 | { 57 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003)); 58 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003)); 59 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_003)); 60 | break; 61 | } 62 | 63 | case PLUGIN_WEBFORM_LOAD: 64 | { 65 | char tmpString[128]; 66 | sprintf_P(tmpString, PSTR("Debounce Time (mSec):"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 67 | string += tmpString; 68 | 69 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 70 | String options[3]; 71 | options[0] = F("Delta"); 72 | options[1] = F("Delta/Total/Time"); 73 | options[2] = F("Total"); 74 | int optionValues[3]; 75 | optionValues[0] = 0; 76 | optionValues[1] = 1; 77 | optionValues[2] = 2; 78 | string += F("Counter Type:"); 91 | 92 | if (choice !=0) 93 | string += F("Total count is not persistent!"); 94 | 95 | success = true; 96 | break; 97 | } 98 | 99 | case PLUGIN_WEBFORM_SAVE: 100 | { 101 | String plugin1 = WebServer.arg(F("plugin_003")); 102 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 103 | String plugin2 = WebServer.arg(F("plugin_003_countertype")); 104 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 105 | success = true; 106 | break; 107 | } 108 | 109 | case PLUGIN_WEBFORM_SHOW_VALUES: 110 | { 111 | string += F("
"); 112 | string += ExtraTaskSettings.TaskDeviceValueNames[0]; 113 | string += F(":
"); 114 | string += Plugin_003_pulseCounter[event->TaskIndex]; 115 | string += F("
"); 116 | string += ExtraTaskSettings.TaskDeviceValueNames[1]; 117 | string += F(":
"); 118 | string += Plugin_003_pulseTotalCounter[event->TaskIndex]; 119 | string += F("
"); 120 | string += ExtraTaskSettings.TaskDeviceValueNames[2]; 121 | string += F(":
"); 122 | string += Plugin_003_pulseTime[event->TaskIndex]; 123 | string += F("
"); 124 | success = true; 125 | break; 126 | } 127 | 128 | case PLUGIN_INIT: 129 | { 130 | String log = F("INIT : Pulse "); 131 | log += Settings.TaskDevicePin1[event->TaskIndex]; 132 | addLog(LOG_LEVEL_INFO,log); 133 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 134 | Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex); 135 | success = true; 136 | break; 137 | } 138 | 139 | case PLUGIN_READ: 140 | { 141 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 142 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 143 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 144 | 145 | switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 146 | { 147 | case 0: 148 | { 149 | event->sensorType = SENSOR_TYPE_SINGLE; 150 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 151 | break; 152 | } 153 | case 1: 154 | { 155 | event->sensorType = SENSOR_TYPE_TRIPLE; 156 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 157 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 158 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 159 | break; 160 | } 161 | case 2: 162 | { 163 | event->sensorType = SENSOR_TYPE_SINGLE; 164 | UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 165 | break; 166 | } 167 | } 168 | Plugin_003_pulseCounter[event->TaskIndex] = 0; 169 | success = true; 170 | break; 171 | } 172 | } 173 | return success; 174 | } 175 | 176 | 177 | /*********************************************************************************************\ 178 | * Check Pulse Counters (called from irq handler) 179 | \*********************************************************************************************/ 180 | void Plugin_003_pulsecheck(byte Index) 181 | { 182 | unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index]; 183 | if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task 184 | { 185 | Plugin_003_pulseCounter[Index]++; 186 | Plugin_003_pulseTotalCounter[Index]++; 187 | Plugin_003_pulseTime[Index] = PulseTime; 188 | Plugin_003_pulseTimePrevious[Index]=millis(); 189 | } 190 | } 191 | 192 | 193 | /*********************************************************************************************\ 194 | * Pulse Counter IRQ handlers 195 | \*********************************************************************************************/ 196 | void Plugin_003_pulse_interrupt1() 197 | { 198 | Plugin_003_pulsecheck(0); 199 | } 200 | void Plugin_003_pulse_interrupt2() 201 | { 202 | Plugin_003_pulsecheck(1); 203 | } 204 | void Plugin_003_pulse_interrupt3() 205 | { 206 | Plugin_003_pulsecheck(2); 207 | } 208 | void Plugin_003_pulse_interrupt4() 209 | { 210 | Plugin_003_pulsecheck(3); 211 | } 212 | void Plugin_003_pulse_interrupt5() 213 | { 214 | Plugin_003_pulsecheck(4); 215 | } 216 | void Plugin_003_pulse_interrupt6() 217 | { 218 | Plugin_003_pulsecheck(5); 219 | } 220 | void Plugin_003_pulse_interrupt7() 221 | { 222 | Plugin_003_pulsecheck(6); 223 | } 224 | void Plugin_003_pulse_interrupt8() 225 | { 226 | Plugin_003_pulsecheck(7); 227 | } 228 | 229 | 230 | /*********************************************************************************************\ 231 | * Init Pulse Counters 232 | \*********************************************************************************************/ 233 | void Plugin_003_pulseinit(byte Par1, byte Index) 234 | { 235 | // Init IO pins 236 | String log = F("PULSE: Init"); 237 | addLog(LOG_LEVEL_INFO,log); 238 | 239 | switch (Index) 240 | { 241 | case 0: 242 | attachInterrupt(Par1, Plugin_003_pulse_interrupt1, FALLING); 243 | break; 244 | case 1: 245 | attachInterrupt(Par1, Plugin_003_pulse_interrupt2, FALLING); 246 | break; 247 | case 2: 248 | attachInterrupt(Par1, Plugin_003_pulse_interrupt3, FALLING); 249 | break; 250 | case 3: 251 | attachInterrupt(Par1, Plugin_003_pulse_interrupt4, FALLING); 252 | break; 253 | case 4: 254 | attachInterrupt(Par1, Plugin_003_pulse_interrupt5, FALLING); 255 | break; 256 | case 5: 257 | attachInterrupt(Par1, Plugin_003_pulse_interrupt6, FALLING); 258 | break; 259 | case 6: 260 | attachInterrupt(Par1, Plugin_003_pulse_interrupt7, FALLING); 261 | break; 262 | case 7: 263 | attachInterrupt(Par1, Plugin_003_pulse_interrupt8, FALLING); 264 | break; 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /_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_INFO, 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 | -------------------------------------------------------------------------------- /_P007_PCF8591.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 007: ExtWiredAnalog ####################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_007 6 | #define PLUGIN_ID_007 7 7 | #define PLUGIN_NAME_007 "Analog input - PCF8591" 8 | #define PLUGIN_VALUENAME1_007 "Analog" 9 | 10 | boolean Plugin_007(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | 14 | static byte portValue = 0; 15 | 16 | switch (function) 17 | { 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_007; 21 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 22 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 23 | Device[deviceCount].Ports = 4; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = true; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = true; 30 | Device[deviceCount].GlobalSyncOption = true; 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_007); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_007)); 43 | break; 44 | } 45 | 46 | case PLUGIN_READ: 47 | { 48 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 49 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 50 | uint8_t address = 0x48 + unit; 51 | 52 | // get the current pin value 53 | Wire.beginTransmission(address); 54 | Wire.write(port - 1); 55 | Wire.endTransmission(); 56 | 57 | Wire.requestFrom(address, (uint8_t)0x2); 58 | if (Wire.available()) 59 | { 60 | Wire.read(); // Read older value first (stored in chip) 61 | UserVar[event->BaseVarIndex] = (float)Wire.read(); // now read actual value and store into Nodo var 62 | String log = F("PCF : Analog value: "); 63 | log += UserVar[event->BaseVarIndex]; 64 | addLog(LOG_LEVEL_INFO,log); 65 | success = true; 66 | } 67 | break; 68 | } 69 | } 70 | return success; 71 | } 72 | 73 | -------------------------------------------------------------------------------- /_P008_RFID.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################################# Plugin 008: Wiegand RFID Tag Reader ################################# 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_008 6 | #define PLUGIN_ID_008 8 7 | #define PLUGIN_NAME_008 "RFID Reader - Wiegand" 8 | #define PLUGIN_VALUENAME1_008 "Tag" 9 | 10 | #define PLUGIN_008_WGSIZE 26 11 | 12 | void Plugin_008_interrupt1() ICACHE_RAM_ATTR; 13 | void Plugin_008_interrupt2() ICACHE_RAM_ATTR; 14 | 15 | volatile byte Plugin_008_bitCount = 0; // Count the number of bits received. 16 | volatile unsigned long Plugin_008_keyBuffer = 0; // A 32-bit-long keyBuffer into which the number is stored. 17 | byte Plugin_008_bitCountPrev = 0; // to detect noise 18 | byte Plugin_008_Unit = 0; 19 | 20 | boolean Plugin_008_init = false; 21 | 22 | boolean Plugin_008(byte function, struct EventStruct *event, String& string) 23 | { 24 | boolean success = false; 25 | 26 | switch (function) 27 | { 28 | case PLUGIN_DEVICE_ADD: 29 | { 30 | Device[++deviceCount].Number = PLUGIN_ID_008; 31 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 32 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 33 | Device[deviceCount].Ports = 0; 34 | Device[deviceCount].PullUpOption = false; 35 | Device[deviceCount].InverseLogicOption = false; 36 | Device[deviceCount].FormulaOption = false; 37 | Device[deviceCount].ValueCount = 1; 38 | Device[deviceCount].SendDataOption = true; 39 | Device[deviceCount].TimerOption = false; 40 | Device[deviceCount].GlobalSyncOption = true; 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICENAME: 45 | { 46 | string = F(PLUGIN_NAME_008); 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICEVALUENAMES: 51 | { 52 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_008)); 53 | break; 54 | } 55 | 56 | case PLUGIN_INIT: 57 | { 58 | Plugin_008_init = true; 59 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 60 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 61 | attachInterrupt(Settings.TaskDevicePin1[event->TaskIndex], Plugin_008_interrupt1, FALLING); 62 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_008_interrupt2, FALLING); 63 | success = true; 64 | break; 65 | } 66 | 67 | case PLUGIN_ONCE_A_SECOND: 68 | { 69 | if (Plugin_008_init) 70 | { 71 | if ((Plugin_008_bitCount != PLUGIN_008_WGSIZE) && (Plugin_008_bitCount == Plugin_008_bitCountPrev)) 72 | { 73 | // must be noise 74 | Plugin_008_bitCount = 0; 75 | Plugin_008_keyBuffer = 0; 76 | } 77 | 78 | if (Plugin_008_bitCount == PLUGIN_008_WGSIZE) 79 | { 80 | Plugin_008_bitCount = 0; // Read in the current key and reset everything so that the interrupts can 81 | 82 | Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 1; // Strip leading and trailing parity bits from the keyBuffer 83 | Plugin_008_keyBuffer &= 0xFFFFFF; 84 | UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); 85 | UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); 86 | String log = F("RFID : Tag: "); 87 | log += Plugin_008_keyBuffer; 88 | addLog(LOG_LEVEL_INFO, log); 89 | sendData(event); 90 | } 91 | 92 | Plugin_008_bitCountPrev = Plugin_008_bitCount; // store this value for next check, detect noise 93 | } 94 | break; 95 | } 96 | } 97 | return success; 98 | } 99 | 100 | /*********************************************************************/ 101 | void Plugin_008_interrupt1() 102 | /*********************************************************************/ 103 | { 104 | // We've received a 1 bit. (bit 0 = high, bit 1 = low) 105 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 106 | Plugin_008_keyBuffer += 1; // Add the 1 (not necessary for the zeroes) 107 | Plugin_008_bitCount++; // Increment the bit count 108 | } 109 | 110 | /*********************************************************************/ 111 | void Plugin_008_interrupt2() 112 | /*********************************************************************/ 113 | { 114 | // We've received a 0 bit. (bit 0 = low, bit 1 = high) 115 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 116 | Plugin_008_bitCount++; // Increment the bit count 117 | } 118 | 119 | -------------------------------------------------------------------------------- /_P010_BH1750.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin-010: LuxRead ############################################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_010 6 | #define PLUGIN_ID_010 10 7 | #define PLUGIN_NAME_010 "Luminosity - BH1750" 8 | #define PLUGIN_VALUENAME1_010 "Lux" 9 | 10 | #define BH1750_ADDRESS_1 0x23 11 | #define BH1750_ADDRESS_2 0x5c 12 | boolean Plugin_010_init_1 = false; 13 | boolean Plugin_010_init_2 = false; 14 | 15 | boolean Plugin_010(byte function, struct EventStruct *event, String& string) 16 | { 17 | boolean success=false; 18 | 19 | switch(function) 20 | { 21 | 22 | case PLUGIN_DEVICE_ADD: 23 | { 24 | Device[++deviceCount].Number = PLUGIN_ID_010; 25 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 26 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 27 | Device[deviceCount].Ports = 0; 28 | Device[deviceCount].PullUpOption = false; 29 | Device[deviceCount].InverseLogicOption = false; 30 | Device[deviceCount].FormulaOption = true; 31 | Device[deviceCount].ValueCount = 1; 32 | Device[deviceCount].SendDataOption = true; 33 | Device[deviceCount].TimerOption = true; 34 | Device[deviceCount].GlobalSyncOption = true; 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICENAME: 39 | { 40 | string = F(PLUGIN_NAME_010); 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICEVALUENAMES: 45 | { 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_010)); 47 | break; 48 | } 49 | 50 | case PLUGIN_WEBFORM_LOAD: 51 | { 52 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 53 | String options[2]; 54 | options[0] = F("0x23 - default settings (ADDR Low)"); 55 | options[1] = F("0x5c - alternate settings (ADDR High)"); 56 | int optionValues[2]; 57 | optionValues[0] = 0; 58 | optionValues[1] = 1; 59 | string += F("I2C Address:"); 72 | 73 | success = true; 74 | break; 75 | } 76 | 77 | case PLUGIN_WEBFORM_SAVE: 78 | { 79 | String plugin1 = WebServer.arg(F("plugin_010")); 80 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_READ: 86 | { 87 | uint8_t address = -1; 88 | boolean *Plugin_010_init; 89 | 90 | if(Settings.TaskDevicePluginConfig[event->TaskIndex][0]==0) 91 | { 92 | address = BH1750_ADDRESS_1; 93 | Plugin_010_init = &Plugin_010_init_1; 94 | } 95 | else 96 | { 97 | address = BH1750_ADDRESS_2; 98 | Plugin_010_init = &Plugin_010_init_2; 99 | } 100 | 101 | if (!*Plugin_010_init) 102 | { 103 | *Plugin_010_init = Plugin_010_setResolution(address); 104 | } 105 | 106 | if (Wire.requestFrom(address, (uint8_t)2) == 2) 107 | { 108 | byte b1 = Wire.read(); 109 | byte b2 = Wire.read(); 110 | float val = 0xffff; //pm-cz: Maximum obtainable value 111 | if (b1 != 0xff || b2 != 0xff) { //pm-cz: Add maximum range check 112 | val=((b1<<8)|b2)/1.2; 113 | } 114 | UserVar[event->BaseVarIndex] = val; 115 | String log = F("LUX 0x"); 116 | log += String(address,HEX); 117 | log += F(" : Light intensity: "); 118 | log += UserVar[event->BaseVarIndex]; 119 | addLog(LOG_LEVEL_INFO,log); 120 | success=true; 121 | } 122 | break; 123 | } 124 | } 125 | return success; 126 | } 127 | 128 | boolean Plugin_010_setResolution(uint8_t address){ 129 | Wire.beginTransmission(address); 130 | Wire.write(0x10); // 1 lx resolution 131 | Wire.endTransmission(); 132 | return true; 133 | } 134 | -------------------------------------------------------------------------------- /_P011_PME.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 011: Pro Mini Extender #################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_011 6 | #define PLUGIN_ID_011 11 7 | #define PLUGIN_NAME_011 "ProMini Extender" 8 | #define PLUGIN_VALUENAME1_011 "Value" 9 | 10 | #define PLUGIN_011_I2C_ADDRESS 0x7f 11 | 12 | boolean Plugin_011(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_011; 22 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 23 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = true; 27 | Device[deviceCount].Ports = 14; 28 | Device[deviceCount].ValueCount = 1; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_011); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_011)); 43 | break; 44 | } 45 | 46 | case PLUGIN_WEBFORM_LOAD: 47 | { 48 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 49 | String options[2]; 50 | options[0] = F("Digital"); 51 | options[1] = F("Analog"); 52 | int optionValues[2]; 53 | optionValues[0] = 0; 54 | optionValues[1] = 1; 55 | string += F("Port Type:"); 68 | 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_WEBFORM_SAVE: 74 | { 75 | String plugin1 = WebServer.arg(F("plugin_011")); 76 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 77 | success = true; 78 | break; 79 | } 80 | 81 | case PLUGIN_READ: 82 | { 83 | UserVar[event->BaseVarIndex] = Plugin_011_Read(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePort[event->TaskIndex]); 84 | String log = F("PME : PortValue: "); 85 | log += UserVar[event->BaseVarIndex]; 86 | addLog(LOG_LEVEL_INFO, log); 87 | success = true; 88 | break; 89 | } 90 | 91 | case PLUGIN_WRITE: 92 | { 93 | String log = ""; 94 | String command = parseString(string, 1); 95 | 96 | if (command == F("extgpio")) 97 | { 98 | success = true; 99 | Plugin_011_Write(event->Par1, event->Par2); 100 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 101 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2); 102 | addLog(LOG_LEVEL_INFO, log); 103 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 104 | } 105 | 106 | if (command == F("extpwm")) 107 | { 108 | success = true; 109 | uint8_t address = PLUGIN_011_I2C_ADDRESS; 110 | Wire.beginTransmission(address); 111 | Wire.write(3); 112 | Wire.write(event->Par1); 113 | Wire.write(event->Par2 & 0xff); 114 | Wire.write((event->Par2 >> 8)); 115 | Wire.endTransmission(); 116 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_PWM, event->Par2); 117 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); 118 | addLog(LOG_LEVEL_INFO, log); 119 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 120 | } 121 | 122 | if (command == F("extpulse")) 123 | { 124 | success = true; 125 | if (event->Par1 >= 0 && event->Par1 <= 13) 126 | { 127 | Plugin_011_Write(event->Par1, event->Par2); 128 | delay(event->Par3); 129 | Plugin_011_Write(event->Par1, !event->Par2); 130 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 131 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS")); 132 | addLog(LOG_LEVEL_INFO, log); 133 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 134 | } 135 | } 136 | 137 | if (command == F("extlongpulse")) 138 | { 139 | success = true; 140 | if (event->Par1 >= 0 && event->Par1 <= 13) 141 | { 142 | Plugin_011_Write(event->Par1, event->Par2); 143 | setSystemTimer(event->Par3 * 1000, PLUGIN_ID_011, event->Par1, !event->Par2, 0); 144 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 145 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S")); 146 | addLog(LOG_LEVEL_INFO, log); 147 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 148 | } 149 | } 150 | 151 | if (command == F("status")) 152 | { 153 | if (parseString(string, 2) == F("ext")) 154 | { 155 | success = true; 156 | String status = ""; 157 | if (hasPinState(PLUGIN_ID_011, event->Par2)) // has been set as output 158 | status = getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par2, dummyString, 0); 159 | else 160 | { 161 | byte port = event->Par2; // port 0-13 is digital, ports 20-27 are mapped to A0-A7 162 | byte type = 0; // digital 163 | if (port > 13) 164 | { 165 | type = 1; 166 | port -= 20; 167 | } 168 | int state = Plugin_011_Read(type, port); // report as input (todo: analog reading) 169 | if (state != -1) 170 | status = getPinStateJSON(NO_SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par2, dummyString, state); 171 | } 172 | SendStatus(event->Source, status); 173 | } 174 | } 175 | 176 | break; 177 | } 178 | 179 | case PLUGIN_TIMER_IN: 180 | { 181 | Plugin_011_Write(event->Par1, event->Par2); 182 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 183 | break; 184 | } 185 | } 186 | return success; 187 | } 188 | 189 | 190 | //******************************************************************************** 191 | // PME read 192 | //******************************************************************************** 193 | int Plugin_011_Read(byte Par1, byte Par2) 194 | { 195 | int value = -1; 196 | uint8_t address = PLUGIN_011_I2C_ADDRESS; 197 | Wire.beginTransmission(address); 198 | if (Par1 == 0) 199 | Wire.write(2); // Digital Read 200 | else 201 | Wire.write(4); // Analog Read 202 | Wire.write(Par2); 203 | Wire.write(0); 204 | Wire.write(0); 205 | Wire.endTransmission(); 206 | delay(1); // remote unit needs some time for conversion... 207 | Wire.requestFrom(address, (uint8_t)0x4); 208 | byte buffer[4]; 209 | if (Wire.available() == 4) 210 | { 211 | for (byte x = 0; x < 4; x++) 212 | buffer[x] = Wire.read(); 213 | value = buffer[0] + 256 * buffer[1]; 214 | } 215 | return value; 216 | } 217 | 218 | 219 | //******************************************************************************** 220 | // PME write 221 | //******************************************************************************** 222 | boolean Plugin_011_Write(byte Par1, byte Par2) 223 | { 224 | uint8_t address = 0x7f; 225 | Wire.beginTransmission(address); 226 | Wire.write(1); 227 | Wire.write(Par1); 228 | Wire.write(Par2 & 0xff); 229 | Wire.write((Par2 >> 8)); 230 | Wire.endTransmission(); 231 | } 232 | 233 | -------------------------------------------------------------------------------- /_P012_LCD.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 012: LCD ################################################## 3 | //####################################################################################################### 4 | 5 | // Sample templates 6 | // Temp: [DHT11#Temperature] Hum:[DHT11#humidity] 7 | // DS Temp:[Dallas1#Temperature#R] 8 | // Lux:[Lux#Lux#R] 9 | // Baro:[Baro#Pressure#R] 10 | 11 | LiquidCrystal_I2C *lcd; 12 | 13 | #define PLUGIN_012 14 | #define PLUGIN_ID_012 12 15 | #define PLUGIN_NAME_012 "Display - LCD2004" 16 | #define PLUGIN_VALUENAME1_012 "LCD" 17 | 18 | boolean Plugin_012(byte function, struct EventStruct *event, String& string) 19 | { 20 | boolean success = false; 21 | static byte displayTimer = 0; 22 | 23 | switch (function) 24 | { 25 | 26 | case PLUGIN_DEVICE_ADD: 27 | { 28 | Device[++deviceCount].Number = PLUGIN_ID_012; 29 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 30 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 31 | Device[deviceCount].Ports = 0; 32 | Device[deviceCount].PullUpOption = false; 33 | Device[deviceCount].InverseLogicOption = false; 34 | Device[deviceCount].FormulaOption = false; 35 | Device[deviceCount].ValueCount = 0; 36 | Device[deviceCount].SendDataOption = false; 37 | Device[deviceCount].TimerOption = true; 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICENAME: 42 | { 43 | string = F(PLUGIN_NAME_012); 44 | break; 45 | } 46 | 47 | case PLUGIN_GET_DEVICEVALUENAMES: 48 | { 49 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_012)); 50 | break; 51 | } 52 | 53 | case PLUGIN_WEBFORM_LOAD: 54 | { 55 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 56 | int optionValues[16]; 57 | for (byte x = 0; x < 17; x++) 58 | if (x < 8) 59 | optionValues[x] = 0x20 + x; 60 | else 61 | optionValues[x] = 0x30 + x; 62 | 63 | string += F("I2C Address:"); 76 | 77 | byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 78 | String options2[2]; 79 | options2[0] = F("2 x 16"); 80 | options2[1] = F("4 x 20"); 81 | int optionValues2[2]; 82 | optionValues2[0] = 1; 83 | optionValues2[1] = 2; 84 | string += F("Display Size:"); 97 | 98 | char deviceTemplate[4][80]; 99 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 100 | for (byte varNr = 0; varNr < 4; varNr++) 101 | { 102 | string += F("Line "); 103 | string += varNr + 1; 104 | string += F(":"); 109 | } 110 | 111 | string += F("Display button:"); 112 | addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]); 113 | 114 | char tmpString[128]; 115 | 116 | sprintf_P(tmpString, PSTR("Display Timeout:"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]); 117 | string += tmpString; 118 | 119 | success = true; 120 | break; 121 | } 122 | 123 | case PLUGIN_WEBFORM_SAVE: 124 | { 125 | String plugin1 = WebServer.arg(F("plugin_012_adr")); 126 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 127 | String plugin2 = WebServer.arg(F("plugin_012_size")); 128 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 129 | String plugin3 = WebServer.arg(F("plugin_12_timer")); 130 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); 131 | 132 | char deviceTemplate[4][80]; 133 | for (byte varNr = 0; varNr < 4; varNr++) 134 | { 135 | char argc[25]; 136 | String arg = F("Plugin_012_template"); 137 | arg += varNr + 1; 138 | arg.toCharArray(argc, 25); 139 | String tmpString = WebServer.arg(argc); 140 | strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])); 141 | } 142 | 143 | SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 144 | success = true; 145 | break; 146 | } 147 | 148 | case PLUGIN_INIT: 149 | { 150 | if (!lcd) 151 | { 152 | byte row = 2; 153 | byte col = 16; 154 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 155 | { 156 | row = 4; 157 | col = 20; 158 | } 159 | lcd = new LiquidCrystal_I2C(Settings.TaskDevicePluginConfig[event->TaskIndex][0], col, row); 160 | } 161 | // Setup LCD display 162 | lcd->init(); // initialize the lcd 163 | lcd->backlight(); 164 | lcd->print("ESP Easy"); 165 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 166 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 167 | pinMode(Settings.TaskDevicePin3[event->TaskIndex], INPUT_PULLUP); 168 | success = true; 169 | break; 170 | } 171 | 172 | case PLUGIN_TEN_PER_SECOND: 173 | { 174 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 175 | { 176 | if (!digitalRead(Settings.TaskDevicePin3[event->TaskIndex])) 177 | { 178 | lcd->backlight(); 179 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 180 | } 181 | } 182 | break; 183 | } 184 | 185 | case PLUGIN_ONCE_A_SECOND: 186 | { 187 | if ( displayTimer > 0) 188 | { 189 | displayTimer--; 190 | if (displayTimer == 0) 191 | lcd->noBacklight(); 192 | } 193 | break; 194 | } 195 | 196 | case PLUGIN_READ: 197 | { 198 | char deviceTemplate[4][80]; 199 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 200 | 201 | byte row = 2; 202 | byte col = 16; 203 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 204 | { 205 | row = 4; 206 | col = 20; 207 | } 208 | 209 | for (byte x = 0; x < row; x++) 210 | { 211 | String tmpString = deviceTemplate[x]; 212 | if (tmpString.length()) 213 | { 214 | String newString = parseTemplate(tmpString, col); 215 | lcd->setCursor(0, x); 216 | lcd->print(newString); 217 | } 218 | } 219 | success = false; 220 | break; 221 | } 222 | 223 | case PLUGIN_WRITE: 224 | { 225 | String tmpString = string; 226 | int argIndex = tmpString.indexOf(','); 227 | if (argIndex) 228 | tmpString = tmpString.substring(0, argIndex); 229 | if (tmpString.equalsIgnoreCase(F("LCD"))) 230 | { 231 | success = true; 232 | argIndex = string.lastIndexOf(','); 233 | tmpString = string.substring(argIndex + 1); 234 | lcd->setCursor(event->Par2 - 1, event->Par1 - 1); 235 | lcd->print(tmpString.c_str()); 236 | } 237 | if (tmpString.equalsIgnoreCase(F("LCDCMD"))) 238 | { 239 | success = true; 240 | argIndex = string.lastIndexOf(','); 241 | tmpString = string.substring(argIndex + 1); 242 | if (tmpString.equalsIgnoreCase(F("Off"))) 243 | lcd->noBacklight(); 244 | else if (tmpString.equalsIgnoreCase(F("On"))) 245 | lcd->backlight(); 246 | else if (tmpString.equalsIgnoreCase(F("Clear"))) 247 | lcd->clear(); 248 | } 249 | break; 250 | } 251 | 252 | } 253 | return success; 254 | } 255 | -------------------------------------------------------------------------------- /_P013_HCSR04.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 013: HC-SR04 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_013 6 | #define PLUGIN_ID_013 13 7 | #define PLUGIN_NAME_013 "Ultrasonic Sensor - HC-SR04" 8 | #define PLUGIN_VALUENAME1_013 "Distance" 9 | 10 | void Plugin_013_interrupt() ICACHE_RAM_ATTR; 11 | 12 | boolean Plugin_013_init = false; 13 | volatile unsigned long Plugin_013_timer = 0; 14 | volatile unsigned long Plugin_013_state = 0; 15 | byte Plugin_013_TRIG_Pin = 0; 16 | byte Plugin_013_IRQ_Pin = 0; 17 | 18 | boolean Plugin_013(byte function, struct EventStruct *event, String& string) 19 | { 20 | static byte switchstate[TASKS_MAX]; 21 | boolean success = false; 22 | 23 | switch (function) 24 | { 25 | case PLUGIN_DEVICE_ADD: 26 | { 27 | Device[++deviceCount].Number = PLUGIN_ID_013; 28 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 29 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 30 | Device[deviceCount].Ports = 0; 31 | Device[deviceCount].PullUpOption = false; 32 | Device[deviceCount].InverseLogicOption = false; 33 | Device[deviceCount].FormulaOption = false; 34 | Device[deviceCount].ValueCount = 1; 35 | Device[deviceCount].SendDataOption = true; 36 | Device[deviceCount].TimerOption = true; 37 | Device[deviceCount].GlobalSyncOption = true; 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICENAME: 42 | { 43 | string = F(PLUGIN_NAME_013); 44 | break; 45 | } 46 | 47 | case PLUGIN_GET_DEVICEVALUENAMES: 48 | { 49 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_013)); 50 | break; 51 | } 52 | 53 | 54 | case PLUGIN_WEBFORM_LOAD: 55 | { 56 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 57 | String options[2]; 58 | options[0] = F("Value"); 59 | options[1] = F("State"); 60 | int optionValues[2]; 61 | optionValues[0] = 1; 62 | optionValues[1] = 2; 63 | string += F("Mode:"); 76 | 77 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 78 | { 79 | char tmpString[128]; 80 | sprintf_P(tmpString, PSTR("Threshold:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 81 | string += tmpString; 82 | } 83 | success = true; 84 | break; 85 | } 86 | 87 | case PLUGIN_WEBFORM_SAVE: 88 | { 89 | String plugin1 = WebServer.arg(F("plugin_013_mode")); 90 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 91 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 92 | { 93 | String plugin2 = WebServer.arg(F("plugin_013_threshold")); 94 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 95 | } 96 | success = true; 97 | break; 98 | } 99 | 100 | case PLUGIN_INIT: 101 | { 102 | Plugin_013_init = true; 103 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 104 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 105 | Plugin_013_IRQ_Pin = Settings.TaskDevicePin2[event->TaskIndex]; 106 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_013_interrupt, CHANGE); 107 | success = true; 108 | break; 109 | } 110 | 111 | case PLUGIN_READ: // If we select value mode, read and send the value based on global timer 112 | { 113 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1) 114 | { 115 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 116 | float value = Plugin_013_read(); 117 | String log = F("SR04 : Distance: "); 118 | if (value != -1) 119 | { 120 | UserVar[event->BaseVarIndex] = (float)Plugin_013_timer / 58; 121 | log += UserVar[event->BaseVarIndex]; 122 | success = true; 123 | } 124 | else 125 | log += F("SR04 : Distance: No reading!"); 126 | 127 | addLog(LOG_LEVEL_INFO,log); 128 | } 129 | break; 130 | } 131 | 132 | case PLUGIN_TEN_PER_SECOND: // If we select state mode, do more frequent checks and send only state changes 133 | { 134 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 135 | { 136 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 137 | byte state = 0; 138 | float value = Plugin_013_read(); 139 | if (value != -1) 140 | { 141 | if (value < Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 142 | state = 1; 143 | if (state != switchstate[event->TaskIndex]) 144 | { 145 | String log = F("SR04 : State "); 146 | log += state; 147 | addLog(LOG_LEVEL_INFO,log); 148 | switchstate[event->TaskIndex] = state; 149 | UserVar[event->BaseVarIndex] = state; 150 | event->sensorType = SENSOR_TYPE_SWITCH; 151 | sendData(event); 152 | } 153 | } 154 | } 155 | success = true; 156 | break; 157 | } 158 | } 159 | return success; 160 | } 161 | 162 | /*********************************************************************/ 163 | float Plugin_013_read() 164 | /*********************************************************************/ 165 | { 166 | float value = -1; 167 | Plugin_013_timer = 0; 168 | Plugin_013_state = 0; 169 | noInterrupts(); 170 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 171 | delayMicroseconds(2); 172 | digitalWrite(Plugin_013_TRIG_Pin, HIGH); 173 | delayMicroseconds(10); 174 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 175 | interrupts(); 176 | 177 | delay(25); // wait for measurement to finish (max 400 cm * 58 uSec = 23uSec) 178 | if (Plugin_013_state == 2) 179 | { 180 | value = (float)Plugin_013_timer / 58; 181 | } 182 | return value; 183 | } 184 | 185 | /*********************************************************************/ 186 | void Plugin_013_interrupt() 187 | /*********************************************************************/ 188 | { 189 | byte pinState = digitalRead(Plugin_013_IRQ_Pin); 190 | if (pinState == 1) // Start of pulse 191 | { 192 | Plugin_013_state = 1; 193 | Plugin_013_timer = micros(); 194 | } 195 | else // End of pulse, calculate timelapse between start & end 196 | { 197 | Plugin_013_state = 2; 198 | Plugin_013_timer = micros() - Plugin_013_timer; 199 | } 200 | } 201 | 202 | -------------------------------------------------------------------------------- /_P016_IR.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 016: Input IR ############################################# 3 | //####################################################################################################### 4 | 5 | #include 6 | IRrecv *irReceiver; 7 | decode_results results; 8 | 9 | #define PLUGIN_016 10 | #define PLUGIN_ID_016 16 11 | #define PLUGIN_NAME_016 "Infrared Receive - TSOP4838" 12 | #define PLUGIN_VALUENAME1_016 "IR" 13 | 14 | boolean Plugin_016(byte function, struct EventStruct *event, String& string) 15 | { 16 | boolean success = false; 17 | 18 | switch (function) 19 | { 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | Device[++deviceCount].Number = PLUGIN_ID_016; 23 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 24 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 25 | Device[deviceCount].Ports = 0; 26 | Device[deviceCount].PullUpOption = true; 27 | Device[deviceCount].InverseLogicOption = true; 28 | Device[deviceCount].FormulaOption = false; 29 | Device[deviceCount].ValueCount = 1; 30 | Device[deviceCount].SendDataOption = true; 31 | Device[deviceCount].TimerOption = false; 32 | Device[deviceCount].GlobalSyncOption = true; 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICENAME: 37 | { 38 | string = F(PLUGIN_NAME_016); 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICEVALUENAMES: 43 | { 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_016)); 45 | break; 46 | } 47 | 48 | case PLUGIN_INIT: 49 | { 50 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 51 | if (irReceiver == 0 && irPin != -1) 52 | { 53 | Serial.println("IR Init"); 54 | irReceiver= new IRrecv(irPin); 55 | irReceiver->enableIRIn(); // Start the receiver 56 | } 57 | if (irReceiver != 0 && irPin == -1) 58 | { 59 | Serial.println("IR Removed"); 60 | irReceiver->disableIRIn(); 61 | delete irReceiver; 62 | irReceiver=0; 63 | } 64 | success = true; 65 | break; 66 | } 67 | 68 | case PLUGIN_TEN_PER_SECOND: 69 | { 70 | if (irReceiver->decode(&results)) 71 | { 72 | unsigned long IRcode = results.value; 73 | irReceiver->resume(); 74 | UserVar[event->BaseVarIndex] = (IRcode & 0xFFFF); 75 | UserVar[event->BaseVarIndex + 1] = ((IRcode >> 16) & 0xFFFF); 76 | String log = F("IR : Code "); 77 | log += String(IRcode, HEX); 78 | addLog(LOG_LEVEL_INFO, log); 79 | sendData(event); 80 | } 81 | success = true; 82 | break; 83 | } 84 | } 85 | return success; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /_P018_Dust.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 018: GP2Y10 ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_018 6 | #define PLUGIN_ID_018 18 7 | #define PLUGIN_NAME_018 "Dust Sensor - Sharp GP2Y10" 8 | #define PLUGIN_VALUENAME1_018 "Dust" 9 | 10 | boolean Plugin_018_init = false; 11 | byte Plugin_GP2Y10_LED_Pin = 0; 12 | 13 | boolean Plugin_018(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_018; 22 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 23 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 24 | Device[deviceCount].Ports = 0; 25 | Device[deviceCount].PullUpOption = false; 26 | Device[deviceCount].InverseLogicOption = false; 27 | Device[deviceCount].FormulaOption = true; 28 | Device[deviceCount].ValueCount = 1; 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_018); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_018)); 44 | break; 45 | } 46 | 47 | case PLUGIN_INIT: 48 | { 49 | Plugin_018_init = true; 50 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 51 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 52 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 53 | success = true; 54 | break; 55 | } 56 | 57 | 58 | case PLUGIN_READ: 59 | { 60 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 61 | noInterrupts(); 62 | byte x; 63 | int value; 64 | value = 0; 65 | for (x = 0; x < 25; x++) 66 | { 67 | digitalWrite(Plugin_GP2Y10_LED_Pin, LOW); 68 | delayMicroseconds(280); 69 | value = value + analogRead(A0); 70 | delayMicroseconds(40); 71 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 72 | delayMicroseconds(9680); 73 | } 74 | interrupts(); 75 | UserVar[event->BaseVarIndex] = (float)value; 76 | String log = F("GPY : Dust value: "); 77 | log += value; 78 | addLog(LOG_LEVEL_INFO, log); 79 | success = true; 80 | break; 81 | } 82 | } 83 | return success; 84 | } 85 | -------------------------------------------------------------------------------- /_P019_PCF8574.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 019: PCF8574 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_019 6 | #define PLUGIN_ID_019 19 7 | #define PLUGIN_NAME_019 "Switch input - PCF8574" 8 | #define PLUGIN_VALUENAME1_019 "Switch" 9 | 10 | boolean Plugin_019(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte switchstate[TASKS_MAX]; 14 | 15 | switch (function) 16 | { 17 | 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_019; 21 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 22 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 23 | Device[deviceCount].Ports = 8; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = true; 30 | Device[deviceCount].TimerOptional = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_019); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_019)); 44 | break; 45 | } 46 | 47 | case PLUGIN_WEBFORM_LOAD: 48 | { 49 | string += F("Send Boot state:"); 50 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 51 | string += F(""); 52 | else 53 | string += F(""); 54 | 55 | success = true; 56 | break; 57 | } 58 | 59 | case PLUGIN_WEBFORM_SAVE: 60 | { 61 | 62 | String plugin1 = WebServer.arg(F("plugin_019_boot")); 63 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on"); 64 | 65 | success = true; 66 | break; 67 | } 68 | 69 | case PLUGIN_INIT: 70 | { 71 | // read and store current state to prevent switching at boot time 72 | switchstate[event->TaskIndex] = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 73 | 74 | // if boot state must be send, inverse default state 75 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 76 | switchstate[event->TaskIndex] = !switchstate[event->TaskIndex]; 77 | 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_TEN_PER_SECOND: 83 | { 84 | int state = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 85 | if (state != -1) 86 | { 87 | if (state != switchstate[event->TaskIndex]) 88 | { 89 | String log = F("PCF : State "); 90 | log += state; 91 | addLog(LOG_LEVEL_INFO, log); 92 | switchstate[event->TaskIndex] = state; 93 | UserVar[event->BaseVarIndex] = state; 94 | event->sensorType = SENSOR_TYPE_SWITCH; 95 | sendData(event); 96 | } 97 | } 98 | success = true; 99 | break; 100 | } 101 | 102 | case PLUGIN_READ: 103 | { 104 | // We do not actually read the pin state as this is already done 10x/second 105 | // Instead we just send the last known state stored in Uservar 106 | String log = F("PCF : State "); 107 | log += UserVar[event->BaseVarIndex]; 108 | addLog(LOG_LEVEL_INFO, log); 109 | success = true; 110 | break; 111 | } 112 | 113 | case PLUGIN_WRITE: 114 | { 115 | String log = ""; 116 | String command = parseString(string, 1); 117 | 118 | if (command == F("pcfgpio")) 119 | { 120 | success = true; 121 | Plugin_019_Write(event->Par1, event->Par2); 122 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 123 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2); 124 | addLog(LOG_LEVEL_INFO, log); 125 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 126 | } 127 | 128 | if (command == F("pcfpulse")) 129 | { 130 | success = true; 131 | Plugin_019_Write(event->Par1, event->Par2); 132 | delay(event->Par3); 133 | Plugin_019_Write(event->Par1, !event->Par2); 134 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 135 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS")); 136 | addLog(LOG_LEVEL_INFO, log); 137 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 138 | } 139 | 140 | if (command == F("pcflongpulse")) 141 | { 142 | success = true; 143 | Plugin_019_Write(event->Par1, event->Par2); 144 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 145 | setSystemTimer(event->Par3 * 1000, PLUGIN_ID_019, event->Par1, !event->Par2, 0); 146 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S")); 147 | addLog(LOG_LEVEL_INFO, log); 148 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 149 | } 150 | 151 | if (command == F("status")) 152 | { 153 | if (parseString(string, 2) == F("pcf")) 154 | { 155 | success = true; 156 | String status = ""; 157 | if (hasPinState(PLUGIN_ID_019, event->Par2)) // has been set as output 158 | status = getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par2, dummyString, 0); 159 | else 160 | { 161 | int state = Plugin_019_Read(event->Par2); // report as input 162 | if (state != -1) 163 | status = getPinStateJSON(NO_SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par2, dummyString, state); 164 | } 165 | SendStatus(event->Source, status); 166 | } 167 | } 168 | 169 | break; 170 | } 171 | 172 | case PLUGIN_TIMER_IN: 173 | { 174 | Plugin_019_Write(event->Par1, event->Par2); 175 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 176 | break; 177 | } 178 | } 179 | return success; 180 | } 181 | 182 | 183 | //******************************************************************************** 184 | // PCF8574 read 185 | //******************************************************************************** 186 | int Plugin_019_Read(byte Par1) 187 | { 188 | int8_t state = -1; 189 | byte unit = (Par1 - 1) / 8; 190 | byte port = Par1 - (unit * 8); 191 | uint8_t address = 0x20 + unit; 192 | if (unit > 7) address += 0x10; 193 | 194 | // get the current pin status 195 | Wire.requestFrom(address, (uint8_t)0x1); 196 | if (Wire.available()) 197 | { 198 | state = ((Wire.read() & _BV(port - 1)) >> (port - 1)); 199 | } 200 | return state; 201 | } 202 | 203 | 204 | //******************************************************************************** 205 | // PCF8574 write 206 | //******************************************************************************** 207 | boolean Plugin_019_Write(byte Par1, byte Par2) 208 | { 209 | boolean success = false; 210 | byte portvalue = 0; 211 | byte unit = (Par1 - 1) / 8; 212 | byte port = Par1 - (unit * 8); 213 | uint8_t address = 0x20 + unit; 214 | if (unit > 7) address += 0x10; 215 | 216 | // get the current pin status 217 | Wire.requestFrom(address, (uint8_t)0x1); 218 | if (Wire.available()) 219 | { 220 | portvalue = Wire.read(); 221 | if (Par2 == 1) 222 | portvalue |= (1 << (port - 1)); 223 | else 224 | portvalue &= ~(1 << (port - 1)); 225 | 226 | // write back new data 227 | Wire.beginTransmission(address); 228 | Wire.write(portvalue); 229 | Wire.endTransmission(); 230 | success = true; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /_P021_Level.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 021: Level Control ######################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_021 6 | #define PLUGIN_ID_021 21 7 | #define PLUGIN_NAME_021 "Level Control" 8 | #define PLUGIN_VALUENAME1_021 "Output" 9 | 10 | boolean Plugin_021(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte switchstate[TASKS_MAX]; 14 | 15 | switch (function) 16 | { 17 | 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_021; 21 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 22 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 23 | Device[deviceCount].Ports = 0; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = false; 30 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_021); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_021)); 42 | break; 43 | } 44 | 45 | case PLUGIN_WEBFORM_LOAD: 46 | { 47 | char tmpString[128]; 48 | 49 | string += F("Check Task:"); 50 | addTaskSelect(string, "plugin_021_task", Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 51 | 52 | LoadTaskSettings(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); // we need to load the values from another task for selection! 53 | string += F("Check Value:"); 54 | addTaskValueSelect(string, "plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 55 | 56 | string += F("Set Value:"); 59 | string += F("Hysteresis:"); 62 | 63 | LoadTaskSettings(event->TaskIndex); // we need to restore our original taskvalues! 64 | success = true; 65 | break; 66 | } 67 | 68 | case PLUGIN_WEBFORM_SAVE: 69 | { 70 | String plugin1 = WebServer.arg(F("plugin_021_task")); 71 | String plugin2 = WebServer.arg(F("plugin_021_value")); 72 | String plugin3 = WebServer.arg(F("plugin_021_setvalue")); 73 | String plugin4 = WebServer.arg(F("plugin_021_hyst")); 74 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 75 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 76 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = plugin3.toFloat(); 77 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = plugin4.toFloat(); 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_REMOTE_CONFIG: 83 | { 84 | Serial.print("levelplugin: "); 85 | Serial.println(string); 86 | String command = parseString(string, 1); 87 | if (command == F("setlevel")) 88 | { 89 | String value = parseString(string, 2); 90 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = value.toFloat(); 91 | Serial.println(value); 92 | SaveSettings(); 93 | success = true; 94 | } 95 | break; 96 | } 97 | 98 | case PLUGIN_INIT: 99 | { 100 | Serial.print(F("INIT : Output ")); 101 | Serial.println(Settings.TaskDevicePin1[event->TaskIndex]); 102 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_TEN_PER_SECOND: 108 | { 109 | // we're checking a var from another task, so calculate that basevar 110 | byte TaskIndex = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 111 | byte BaseVarIndex = TaskIndex * VARS_PER_TASK + Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 112 | float value = UserVar[BaseVarIndex]; 113 | byte state = switchstate[event->TaskIndex]; 114 | // compare with threshold value 115 | float valueLowThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] - (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 116 | float valueHighThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] + (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 117 | if (value <= valueLowThreshold) 118 | state = 1; 119 | if (value >= valueHighThreshold) 120 | state = 0; 121 | if (state != switchstate[event->TaskIndex]) 122 | { 123 | Serial.print(F("Out : State ")); 124 | Serial.println(state); 125 | switchstate[event->TaskIndex] = state; 126 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex],state); 127 | UserVar[event->BaseVarIndex] = state; 128 | sendData(event); 129 | } 130 | 131 | success = true; 132 | break; 133 | } 134 | 135 | } 136 | return success; 137 | } 138 | 139 | -------------------------------------------------------------------------------- /_P022_PCA9685.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 022: PCA9685 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_022 6 | #define PLUGIN_ID_022 22 7 | #define PLUGIN_NAME_022 "PWM - PCA9685" 8 | #define PLUGIN_VALUENAME1_022 "PWM" 9 | 10 | #define PCA9685_MODE1 0x00 // location for Mode1 register address 11 | #define PCA9685_MODE2 0x01 // location for Mode2 reigster address 12 | #define PCA9685_LED0 0x06 // location for start of LED0 registers 13 | #define PCA9685_ADDRESS 0x40 // I2C address 14 | 15 | boolean Plugin_022_init = false; 16 | 17 | boolean Plugin_022(byte function, struct EventStruct *event, String& string) 18 | { 19 | boolean success = false; 20 | static byte switchstate[TASKS_MAX]; 21 | 22 | switch (function) 23 | { 24 | case PLUGIN_DEVICE_ADD: 25 | { 26 | Device[++deviceCount].Number = PLUGIN_ID_022; 27 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 28 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 29 | Device[deviceCount].Ports = 0; 30 | Device[deviceCount].PullUpOption = false; 31 | Device[deviceCount].InverseLogicOption = false; 32 | Device[deviceCount].FormulaOption = false; 33 | Device[deviceCount].ValueCount = 0; 34 | Device[deviceCount].Custom = true; 35 | Device[deviceCount].TimerOption = false; 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICENAME: 40 | { 41 | string = F(PLUGIN_NAME_022); 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICEVALUENAMES: 46 | { 47 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_022)); 48 | break; 49 | } 50 | 51 | case PLUGIN_WRITE: 52 | { 53 | String log = ""; 54 | String command = parseString(string, 1); 55 | 56 | if (command == F("pcapwm")) 57 | { 58 | if (!Plugin_022_init) Plugin_022_initialize(); 59 | success = true; 60 | Plugin_022_Write(event->Par1, event->Par2); 61 | setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_PWM, event->Par2); 62 | log = String(F("PCA : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); 63 | addLog(LOG_LEVEL_INFO, log); 64 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0)); 65 | } 66 | 67 | if (command == F("status")) 68 | { 69 | if (parseString(string, 2) == F("pca")) 70 | { 71 | if (!Plugin_022_init) Plugin_022_initialize(); 72 | success = true; 73 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par2, dummyString, 0)); 74 | } 75 | } 76 | break; 77 | } 78 | } 79 | return success; 80 | } 81 | 82 | 83 | //******************************************************************************** 84 | // PCA9685 config 85 | //******************************************************************************** 86 | void Plugin_022_writeRegister(int regAddress, byte data) { 87 | Wire.beginTransmission(PCA9685_ADDRESS); 88 | Wire.write(regAddress); 89 | Wire.write(data); 90 | Wire.endTransmission(); 91 | } 92 | 93 | 94 | //******************************************************************************** 95 | // PCA9685 write 96 | //******************************************************************************** 97 | boolean Plugin_022_Write(byte Par1, int Par2) 98 | { 99 | boolean success = false; 100 | uint16_t LED_ON = 0; 101 | uint16_t LED_OFF = Par2; 102 | Wire.beginTransmission(PCA9685_ADDRESS); 103 | Wire.write(0x06 + 4 * Par1); 104 | Wire.write(lowByte(LED_ON)); 105 | Wire.write(highByte(LED_ON)); 106 | Wire.write(lowByte(LED_OFF)); 107 | Wire.write(highByte(LED_OFF)); 108 | Wire.endTransmission(); 109 | } 110 | 111 | void Plugin_022_initialize() 112 | { 113 | // default mode is open drain ouput, drive leds connected to VCC 114 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)0x01); // reset the device 115 | delay(1); 116 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)B10100000); // set up for auto increment 117 | Plugin_022_writeRegister(PCA9685_MODE2, (byte)0x10); // set to output 118 | Plugin_022_init = true; 119 | } 120 | 121 | -------------------------------------------------------------------------------- /_P024_MLX90614.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 024: MLX90614 IR temperature I2C 0x5A) ############################################### 3 | //####################################################################################################### 4 | 5 | // MyMessage *msgTemp024; // Mysensors 6 | 7 | #define PLUGIN_024 8 | #define PLUGIN_ID_024 24 9 | #define PLUGIN_NAME_024 "Temperature IR + ambient - MLX90614" 10 | #define PLUGIN_VALUENAME1_024 "Temperature" 11 | 12 | boolean Plugin_024_init = false; 13 | 14 | uint16_t readRegister024(uint8_t i2cAddress, uint8_t reg) { 15 | uint16_t ret; 16 | Wire.beginTransmission(i2cAddress); 17 | Wire.write(reg); 18 | Wire.endTransmission(false); 19 | Wire.requestFrom(i2cAddress, (uint8_t)3); 20 | ret = Wire.read(); // receive DATA 21 | ret |= Wire.read() << 8; // receive DATA 22 | uint8_t pec = Wire.read(); 23 | return ret; 24 | } 25 | 26 | float readTemp024(uint8_t i2c_addr, uint8_t i2c_reg) 27 | { 28 | float temp; 29 | temp = readRegister024(i2c_addr, i2c_reg); 30 | temp *= .02; 31 | temp -= 273.15; 32 | return temp; 33 | } 34 | 35 | boolean Plugin_024(byte function, struct EventStruct *event, String& string) 36 | { 37 | boolean success = false; 38 | static byte portValue = 0; 39 | switch (function) 40 | { 41 | case PLUGIN_DEVICE_ADD: 42 | { 43 | Device[++deviceCount].Number = PLUGIN_ID_024; 44 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 45 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 46 | Device[deviceCount].Ports = 16; 47 | Device[deviceCount].PullUpOption = false; 48 | Device[deviceCount].InverseLogicOption = false; 49 | Device[deviceCount].FormulaOption = true; 50 | Device[deviceCount].SendDataOption = true; 51 | Device[deviceCount].ValueCount = 1; 52 | Device[deviceCount].TimerOption = true; 53 | Device[deviceCount].GlobalSyncOption = true; 54 | break; 55 | } 56 | 57 | case PLUGIN_GET_DEVICENAME: 58 | { 59 | string = F(PLUGIN_NAME_024); 60 | break; 61 | } 62 | 63 | case PLUGIN_GET_DEVICEVALUENAMES: 64 | { 65 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_024)); 66 | break; 67 | } 68 | 69 | case PLUGIN_WEBFORM_LOAD: 70 | { 71 | #define MLX90614_OPTION 2 72 | 73 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 74 | String options[MLX90614_OPTION]; 75 | uint optionValues[MLX90614_OPTION]; 76 | optionValues[0] = (0x07); 77 | options[0] = F("IR object temperature"); 78 | optionValues[1] = (0x06); 79 | options[1] = F("Ambient temperature"); 80 | string += F("Option:"); 93 | 94 | success = true; 95 | break; 96 | } 97 | 98 | case PLUGIN_WEBFORM_SAVE: 99 | { 100 | String plugin1 = WebServer.arg(F("plugin_024_option")); 101 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 102 | Plugin_024_init = false; // Force device setup next time 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_INIT: 108 | { 109 | Plugin_024_init = true; 110 | // if (!msgTemp024) // Mysensors 111 | // msgTemp024 = new MyMessage(event->BaseVarIndex, V_TEMP); //Mysensors 112 | // present(event->BaseVarIndex, S_TEMP); //Mysensors 113 | // Serial.print("Present MLX90614: "); //Mysensors 114 | // Serial.println(event->BaseVarIndex); //Mysensors 115 | success = true; 116 | break; 117 | } 118 | 119 | case PLUGIN_READ: 120 | { 121 | // noInterrupts(); 122 | int value; 123 | value = 0; 124 | byte unit = Settings.TaskDevicePort[event->TaskIndex]; 125 | uint8_t address = 0x5A + unit; 126 | UserVar[event->BaseVarIndex] = (float) readTemp024(address, Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 127 | String log = F("MLX90614 : Temperature: "); 128 | log += UserVar[event->BaseVarIndex]; 129 | // send(msgObjTemp024->set(UserVar[event->BaseVarIndex], 1)); // Mysensors 130 | addLog(LOG_LEVEL_INFO,log); 131 | success = true; 132 | // interrupts(); 133 | break; 134 | } 135 | } 136 | return success; 137 | } 138 | -------------------------------------------------------------------------------- /_P025_ADS1115.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 025: ADS1115 I2C 0x48) ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_025 6 | #define PLUGIN_ID_025 25 7 | #define PLUGIN_NAME_025 "Analog input - ADS1115" 8 | #define PLUGIN_VALUENAME1_025 "Analog" 9 | 10 | boolean Plugin_025_init = false; 11 | 12 | static uint16_t readRegister025(uint8_t i2cAddress, uint8_t reg) { 13 | Wire.beginTransmission(i2cAddress); 14 | Wire.write((0x00)); 15 | Wire.endTransmission(); 16 | Wire.requestFrom(i2cAddress, (uint8_t)2); 17 | return ((Wire.read() << 8) | Wire.read()); 18 | } 19 | 20 | boolean Plugin_025(byte function, struct EventStruct *event, String& string) 21 | { 22 | boolean success = false; 23 | static byte portValue = 0; 24 | switch (function) 25 | { 26 | case PLUGIN_DEVICE_ADD: 27 | { 28 | Device[++deviceCount].Number = PLUGIN_ID_025; 29 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 30 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 31 | Device[deviceCount].Ports = 4; 32 | Device[deviceCount].PullUpOption = false; 33 | Device[deviceCount].InverseLogicOption = false; 34 | Device[deviceCount].FormulaOption = true; 35 | Device[deviceCount].ValueCount = 1; 36 | Device[deviceCount].SendDataOption = true; 37 | Device[deviceCount].TimerOption = true; 38 | Device[deviceCount].GlobalSyncOption = true; 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICENAME: 43 | { 44 | string = F(PLUGIN_NAME_025); 45 | break; 46 | } 47 | 48 | case PLUGIN_GET_DEVICEVALUENAMES: 49 | { 50 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_025)); 51 | break; 52 | } 53 | 54 | case PLUGIN_WEBFORM_LOAD: 55 | { 56 | #define ADS1115_GAIN_OPTION 6 57 | 58 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 59 | String options[ADS1115_GAIN_OPTION]; 60 | uint optionValues[ADS1115_GAIN_OPTION]; 61 | optionValues[0] = (0x00); 62 | options[0] = F("2/3x gain 6.144V 0.1875mV"); 63 | optionValues[1] = (0x02); 64 | options[1] = F("1x gain 4.096V 0.125mV"); 65 | optionValues[2] = (0x04); 66 | options[2] = F("2x gain 2.048V 0.0625mV"); 67 | optionValues[3] = (0x06); 68 | options[3] = F("4x gain 1.024V 0.03125mV"); 69 | optionValues[4] = (0x08); 70 | options[4] = F("8x gain 0.512V 0.015625mV"); 71 | optionValues[5] = (0x0A); 72 | options[5] = F("16x gain 0.256V 0.0078125mV"); 73 | 74 | string += F("Gain:"); 87 | 88 | success = true; 89 | break; 90 | } 91 | 92 | case PLUGIN_WEBFORM_SAVE: 93 | { 94 | String plugin1 = WebServer.arg(F("plugin_025_gain")); 95 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 96 | Plugin_025_init = false; // Force device setup next time 97 | success = true; 98 | break; 99 | } 100 | 101 | case PLUGIN_INIT: 102 | { 103 | Plugin_025_init = true; 104 | success = true; 105 | break; 106 | } 107 | 108 | case PLUGIN_READ: 109 | { 110 | uint8_t m_gain = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 111 | int value; 112 | value = 0; 113 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 114 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 115 | uint8_t address = 0x48 + unit; 116 | // get the current pin value 117 | 118 | uint16_t config = (0x0003) | // Disable the comparator (default val) 119 | (0x0000) | // Non-latching (default val) 120 | (0x0000) | // Alert/Rdy active low (default val) 121 | (0x0000) | // Traditional comparator (default val) 122 | (0x0080) | // 1600 samples per second (default) 123 | (0x0100) ; // Single-shot mode (default) 124 | 125 | // m_Gain = (0x0000); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) 126 | // m_Gain = (0x0200); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV 127 | // m_Gain = (0x0400); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV 128 | // m_Gain = (0x0600); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV 129 | // m_Gain = (0x0800); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV 130 | // m_Gain = (0x0A00); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV 131 | // config |= m_gain; 132 | // config |= (0x0000); 133 | switch (m_gain) 134 | { 135 | case (0x00): 136 | config |= (0x0000); 137 | break; 138 | case (0x02): 139 | config |= (0x0200); 140 | break; 141 | case (0x04): 142 | config |= (0x0400); 143 | break; 144 | case (0x06): 145 | config |= (0x0600); 146 | break; 147 | case (0x08): 148 | config |= (0x0800); 149 | break; 150 | case (0x0A): 151 | config |= (0x0A00); 152 | break; 153 | } 154 | switch (port) 155 | { 156 | case (1): 157 | config |= (0x4000); 158 | break; 159 | case (2): 160 | config |= (0x5000); 161 | break; 162 | case (3): 163 | config |= (0x6000); 164 | break; 165 | case (4): 166 | config |= (0x7000); 167 | break; 168 | } 169 | config |= (0x8000); 170 | Wire.beginTransmission(address); 171 | Wire.write((uint8_t)(0x01)); 172 | Wire.write((uint8_t)(config>>8)); 173 | Wire.write((uint8_t)(config & 0xFF)); 174 | Wire.endTransmission(); 175 | delay(8); 176 | UserVar[event->BaseVarIndex] = (float) readRegister025((address), (0x00)) ; 177 | String log = F("ADS1115 : Analog value: "); 178 | log += UserVar[event->BaseVarIndex]; 179 | addLog(LOG_LEVEL_INFO,log); 180 | success = true; 181 | break; 182 | } 183 | } 184 | return success; 185 | } 186 | -------------------------------------------------------------------------------- /_P026_Sysinfo.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 026: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_026 6 | #define PLUGIN_ID_026 26 7 | #define PLUGIN_NAME_026 "System Info" 8 | #define PLUGIN_VALUENAME1_026 "" 9 | 10 | boolean Plugin_026(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | 14 | switch (function) 15 | { 16 | 17 | case PLUGIN_DEVICE_ADD: 18 | { 19 | Device[++deviceCount].Number = PLUGIN_ID_026; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].ValueCount = 1; 22 | Device[deviceCount].SendDataOption = true; 23 | Device[deviceCount].TimerOption = true; 24 | Device[deviceCount].FormulaOption = true; 25 | break; 26 | } 27 | 28 | case PLUGIN_GET_DEVICENAME: 29 | { 30 | string = F(PLUGIN_NAME_026); 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICEVALUENAMES: 35 | { 36 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_026)); 37 | break; 38 | } 39 | 40 | case PLUGIN_WEBFORM_LOAD: 41 | { 42 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 43 | String options[5]; 44 | options[0] = F("Uptime"); 45 | options[1] = F("Free RAM"); 46 | options[2] = F("Wifi RSSI"); 47 | options[3] = F("Input VCC"); 48 | options[4] = F("System load"); 49 | int optionValues[5]; 50 | optionValues[0] = 0; 51 | optionValues[1] = 1; 52 | optionValues[2] = 2; 53 | optionValues[3] = 3; 54 | optionValues[4] = 4; 55 | string += F("Indicator:"); 68 | 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_WEBFORM_SAVE: 74 | { 75 | String plugin1 = WebServer.arg(F("plugin_026")); 76 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 77 | success = true; 78 | break; 79 | } 80 | 81 | case PLUGIN_READ: 82 | { 83 | float value = 0; 84 | switch(Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 85 | { 86 | case 0: 87 | { 88 | value = (wdcounter /2); 89 | break; 90 | } 91 | case 1: 92 | { 93 | value = ESP.getFreeHeap(); 94 | break; 95 | } 96 | case 2: 97 | { 98 | value = WiFi.RSSI(); 99 | break; 100 | } 101 | case 3: 102 | { 103 | #if FEATURE_ADC_VCC 104 | value = vcc; 105 | #else 106 | value = -1.0; 107 | #endif 108 | break; 109 | } 110 | case 4: 111 | { 112 | value = (100 - (100 * loopCounterLast / loopCounterMax)); 113 | break; 114 | } 115 | } 116 | UserVar[event->BaseVarIndex] = value; 117 | String log = F("SYS : "); 118 | log += value; 119 | addLog(LOG_LEVEL_INFO,log); 120 | success = true; 121 | break; 122 | } 123 | } 124 | return success; 125 | } 126 | -------------------------------------------------------------------------------- /_P029_Output.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 029: Output ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_029 6 | #define PLUGIN_ID_029 29 7 | #define PLUGIN_NAME_029 "Output - (Domoticz MQTT helper)" 8 | #define PLUGIN_VALUENAME1_029 "Output" 9 | boolean Plugin_029(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_029; 19 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 20 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = false; 25 | Device[deviceCount].ValueCount = 1; 26 | Device[deviceCount].SendDataOption = false; 27 | break; 28 | } 29 | 30 | case PLUGIN_GET_DEVICENAME: 31 | { 32 | string = F(PLUGIN_NAME_029); 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICEVALUENAMES: 37 | { 38 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_029)); 39 | break; 40 | } 41 | 42 | case PLUGIN_INIT: 43 | { 44 | success = true; 45 | break; 46 | } 47 | } 48 | return success; 49 | } 50 | -------------------------------------------------------------------------------- /_P031_SHT1X.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 031: SHT10/SHT11/SHT15 Temp/Humidity Sensor ############################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_031 6 | #define PLUGIN_ID_031 31 7 | #define PLUGIN_NAME_031 "Temperature & Humidity - SHT1X" 8 | #define PLUGIN_VALUENAME1_031 "Temperature" 9 | #define PLUGIN_VALUENAME2_031 "Humidity" 10 | 11 | boolean Plugin_031_init = false; 12 | byte Plugin_031_DATA_Pin = 0; 13 | byte Plugin_031_CLOCK_Pin = 0; 14 | int input_mode; 15 | 16 | enum { 17 | SHT1X_CMD_MEASURE_TEMP = B00000011, 18 | SHT1X_CMD_MEASURE_RH = B00000101, 19 | SHT1X_CMD_READ_STATUS = B00000111, 20 | SHT1X_CMD_SOFT_RESET = B00011110 21 | }; 22 | 23 | boolean Plugin_031(byte function, struct EventStruct *event, String& string) 24 | { 25 | boolean success = false; 26 | 27 | switch (function) 28 | { 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_031; 32 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 33 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 34 | Device[deviceCount].Ports = 0; 35 | Device[deviceCount].PullUpOption = true; 36 | Device[deviceCount].InverseLogicOption = false; 37 | Device[deviceCount].FormulaOption = true; 38 | Device[deviceCount].ValueCount = 2; 39 | Device[deviceCount].SendDataOption = true; 40 | Device[deviceCount].TimerOption = true; 41 | Device[deviceCount].GlobalSyncOption = true; 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICENAME: 46 | { 47 | string = F(PLUGIN_NAME_031); 48 | break; 49 | } 50 | 51 | case PLUGIN_GET_DEVICEVALUENAMES: 52 | { 53 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_031)); 54 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_031)); 55 | break; 56 | } 57 | 58 | case PLUGIN_INIT: 59 | { 60 | Plugin_031_init = true; 61 | Plugin_031_DATA_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 62 | Plugin_031_CLOCK_Pin = Settings.TaskDevicePin2[event->TaskIndex]; 63 | if (Settings.TaskDevicePin1PullUp[event->TaskIndex]) { 64 | input_mode = INPUT_PULLUP; 65 | String log = F("SHT1X: Setting PullUp on pin "); 66 | log += String(Plugin_031_DATA_Pin); 67 | addLog(LOG_LEVEL_DEBUG, log); 68 | } 69 | else { 70 | input_mode = INPUT; 71 | } 72 | pinMode(Plugin_031_DATA_Pin, input_mode); /* Keep Hi-Z except when sending data */ 73 | pinMode(Plugin_031_CLOCK_Pin, OUTPUT); 74 | Plugin_031_reset(); 75 | byte status = Plugin_031_readStatus(); 76 | String log = F("SHT1X : Status byte: "); 77 | log += String(status, HEX); 78 | log += F(" - resolution: "); 79 | log += (status & 1 ? "low" : "high"); 80 | log += F(" reload from OTP: "); 81 | log += ((status >> 1) & 1 ? "yes" : "no"); 82 | log += F(", heater: "); 83 | log += ((status >> 2) & 1 ? "on" : "off"); 84 | addLog(LOG_LEVEL_DEBUG, log); 85 | success = true; 86 | break; 87 | } 88 | 89 | case PLUGIN_READ: 90 | { 91 | if (!Plugin_031_init) { 92 | String log = F("SHT1X : not yet initialized!"); 93 | addLog(LOG_LEVEL_ERROR, log); 94 | break; 95 | } 96 | UserVar[event->BaseVarIndex] = Plugin_031_readTemperature(); 97 | UserVar[event->BaseVarIndex+1] = Plugin_031_readRelHumidity(UserVar[event->BaseVarIndex]); 98 | success = true; 99 | break; 100 | } 101 | } 102 | return success; 103 | } 104 | 105 | float Plugin_031_readTemperature() 106 | { 107 | float tempRaw, tempC; 108 | 109 | Plugin_031_sendCommand(SHT1X_CMD_MEASURE_TEMP); 110 | Plugin_031_awaitResult(); 111 | tempRaw = Plugin_031_readData(16); 112 | 113 | // Temperature conversion coefficients from SHT1X datasheet for version 4 114 | const float d1 = -39.7; // 3.5V 115 | const float d2 = 0.01; // 14-bit 116 | 117 | tempC = d1 + (tempRaw * d2); 118 | 119 | String log = F("SHT1X : Read temperature (raw): "); 120 | log += String(tempRaw); 121 | log += " (Celcius): "; 122 | log += String(tempC); 123 | addLog(LOG_LEVEL_DEBUG, log); 124 | 125 | return tempC; 126 | } 127 | 128 | float Plugin_031_readRelHumidity(float tempC) 129 | { 130 | float raw, rhLinear, rhTrue; 131 | 132 | Plugin_031_sendCommand(SHT1X_CMD_MEASURE_RH); 133 | Plugin_031_awaitResult(); 134 | raw = Plugin_031_readData(16); 135 | 136 | // Temperature conversion coefficients from SHT1X datasheet for version 4 137 | const float c1 = -2.0468; 138 | const float c2 = 0.0367; 139 | const float c3 = -1.5955E-6; 140 | const float t1 = 0.01; 141 | const float t2 = 0.00008; 142 | 143 | rhLinear = c1 + c2 * raw + c3 * raw * raw; 144 | rhTrue = (tempC - 25) * (t1 + t2 * raw) + rhLinear; 145 | 146 | String log = F("SHT1X : Read humidity (raw): "); 147 | log += String(raw); 148 | log += " (Linear): "; 149 | log += String(rhLinear); 150 | log += " (True): "; 151 | log += String(rhTrue); 152 | addLog(LOG_LEVEL_DEBUG, log); 153 | 154 | return rhTrue; 155 | } 156 | 157 | 158 | void Plugin_031_reset() 159 | { 160 | delay(11); 161 | for (int i=0; i<9; i++) { 162 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 163 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 164 | } 165 | Plugin_031_sendCommand(SHT1X_CMD_SOFT_RESET); 166 | delay(11); 167 | } 168 | 169 | byte Plugin_031_readStatus() 170 | { 171 | Plugin_031_sendCommand(SHT1X_CMD_READ_STATUS); 172 | return Plugin_031_readData(8); 173 | } 174 | 175 | void Plugin_031_sendCommand(const byte cmd) 176 | { 177 | pinMode(Plugin_031_DATA_Pin, OUTPUT); 178 | 179 | // Transmission Start sequence 180 | digitalWrite(Plugin_031_DATA_Pin, HIGH); 181 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 182 | digitalWrite(Plugin_031_DATA_Pin, LOW); 183 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 184 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 185 | digitalWrite(Plugin_031_DATA_Pin, HIGH); 186 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 187 | 188 | // Send the command (address must be 000b) 189 | shiftOut(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, MSBFIRST, cmd); 190 | 191 | // Wait for ACK 192 | bool ackerror = false; 193 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 194 | pinMode(Plugin_031_DATA_Pin, input_mode); 195 | if (digitalRead(Plugin_031_DATA_Pin) != LOW) ackerror = true; 196 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 197 | 198 | if (cmd == SHT1X_CMD_MEASURE_TEMP || cmd == SHT1X_CMD_MEASURE_RH) { 199 | delayMicroseconds(1); /* Give the sensor time to release the data line */ 200 | if (digitalRead(Plugin_031_DATA_Pin) != HIGH) ackerror = true; 201 | } 202 | 203 | if (ackerror) { 204 | String log = F("SHT1X : Sensor did not ACK command"); 205 | addLog(LOG_LEVEL_ERROR, log); 206 | } 207 | } 208 | 209 | void Plugin_031_awaitResult() 210 | { 211 | // Maximum 320ms for 14 bit measurement 212 | for (int i=0; i<16; i++) { 213 | if (digitalRead(Plugin_031_DATA_Pin) == LOW) return; 214 | delay(20); 215 | } 216 | if (digitalRead(Plugin_031_DATA_Pin) != LOW) { 217 | String log = F("SHT1X : Data not ready"); 218 | addLog(LOG_LEVEL_ERROR, log); 219 | } 220 | } 221 | 222 | int Plugin_031_readData(const int bits) 223 | { 224 | int val = 0; 225 | 226 | if (bits == 16) { 227 | // Read most significant byte 228 | val = shiftIn(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, 8); 229 | val <<= 8; 230 | 231 | // Send ACK 232 | pinMode(Plugin_031_DATA_Pin, OUTPUT); 233 | digitalWrite(Plugin_031_DATA_Pin, LOW); 234 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 235 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 236 | pinMode(Plugin_031_DATA_Pin, input_mode); 237 | } 238 | 239 | // Read least significant byte 240 | val |= shiftIn(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, 8); 241 | 242 | // Keep DATA pin high to skip CRC 243 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 244 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 245 | 246 | return val; 247 | } 248 | -------------------------------------------------------------------------------- /_P033_Dummy.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 033: Dummy ################################################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_033 6 | #define PLUGIN_ID_033 33 7 | #define PLUGIN_NAME_033 "Dummy Device" 8 | #define PLUGIN_VALUENAME1_033 "Dummy" 9 | boolean Plugin_033(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_033; 19 | Device[deviceCount].Type = DEVICE_TYPE_DUMMY; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = false; 25 | Device[deviceCount].DecimalsOnly = true; 26 | Device[deviceCount].ValueCount = 4; 27 | Device[deviceCount].SendDataOption = true; 28 | Device[deviceCount].TimerOption = true; 29 | Device[deviceCount].GlobalSyncOption = true; 30 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_033); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_033)); 42 | break; 43 | } 44 | 45 | case PLUGIN_WEBFORM_LOAD: 46 | { 47 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 48 | String options[9]; 49 | options[0] = F("SENSOR_TYPE_SINGLE"); 50 | options[1] = F("SENSOR_TYPE_TEMP_HUM"); 51 | options[2] = F("SENSOR_TYPE_TEMP_BARO"); 52 | options[3] = F("SENSOR_TYPE_TEMP_HUM_BARO"); 53 | options[4] = F("SENSOR_TYPE_DUAL"); 54 | options[5] = F("SENSOR_TYPE_TRIPLE"); 55 | options[6] = F("SENSOR_TYPE_QUAD"); 56 | options[7] = F("SENSOR_TYPE_SWITCH"); 57 | options[8] = F("SENSOR_TYPE_DIMMER"); 58 | int optionValues[9]; 59 | optionValues[0] = SENSOR_TYPE_SINGLE; 60 | optionValues[1] = SENSOR_TYPE_TEMP_HUM; 61 | optionValues[2] = SENSOR_TYPE_TEMP_BARO; 62 | optionValues[3] = SENSOR_TYPE_TEMP_HUM_BARO; 63 | optionValues[4] = SENSOR_TYPE_DUAL; 64 | optionValues[5] = SENSOR_TYPE_TRIPLE; 65 | optionValues[6] = SENSOR_TYPE_QUAD; 66 | optionValues[7] = SENSOR_TYPE_SWITCH; 67 | optionValues[8] = SENSOR_TYPE_DIMMER; 68 | string += F("Simulate Data Type:"); 81 | 82 | success = true; 83 | break; 84 | } 85 | 86 | case PLUGIN_WEBFORM_SAVE: 87 | { 88 | String plugin1 = WebServer.arg(F("plugin_033_sensortype")); 89 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 90 | success = true; 91 | break; 92 | } 93 | 94 | case PLUGIN_READ: 95 | { 96 | event->sensorType =Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 97 | for (byte x=0; x<4;x++) 98 | { 99 | String log = F("Dummy: value "); 100 | log += x+1; 101 | log += F(": "); 102 | log += UserVar[event->BaseVarIndex+x]; 103 | addLog(LOG_LEVEL_INFO,log); 104 | } 105 | success = true; 106 | break; 107 | } 108 | } 109 | return success; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /_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 | /* 91 | log = F("DHT12: Data: "); 92 | for (int i=0; i < 5; i++) 93 | { 94 | log += dht_dat[i]; 95 | log += ", "; 96 | } 97 | addLog(LOG_LEVEL_INFO, log); 98 | */ 99 | success = true; 100 | } // checksum 101 | } // error 102 | if(!success) 103 | { 104 | String log = F("DHT12: No reading!"); 105 | addLog(LOG_LEVEL_INFO, log); 106 | UserVar[event->BaseVarIndex] = NAN; 107 | UserVar[event->BaseVarIndex + 1] = NAN; 108 | } 109 | break; 110 | } 111 | } 112 | return success; 113 | } 114 | -------------------------------------------------------------------------------- /_P035_IRTX.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 035: Output IR ############################################ 3 | //####################################################################################################### 4 | 5 | #include 6 | IRsend *Plugin_035_irSender; 7 | 8 | #define PLUGIN_035 9 | #define PLUGIN_ID_035 35 10 | #define PLUGIN_NAME_035 "Infrared Transmit" 11 | 12 | boolean Plugin_035(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_035; 21 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 22 | Device[deviceCount].SendDataOption = false; 23 | break; 24 | } 25 | 26 | case PLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(PLUGIN_NAME_035); 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICEVALUENAMES: 33 | { 34 | break; 35 | } 36 | 37 | case PLUGIN_INIT: 38 | { 39 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 40 | if (Plugin_035_irSender == 0 && irPin != -1) 41 | { 42 | String log = F("INIT: IR TX"); 43 | addLog(LOG_LEVEL_INFO, log); 44 | Plugin_035_irSender = new IRsend(irPin); 45 | Plugin_035_irSender->begin(); // Start the sender 46 | } 47 | if (Plugin_035_irSender != 0 && irPin == -1) 48 | { 49 | String log = F("INIT: IR TX Removed"); 50 | addLog(LOG_LEVEL_INFO, log); 51 | delete Plugin_035_irSender; 52 | Plugin_035_irSender = 0; 53 | } 54 | success = true; 55 | break; 56 | } 57 | 58 | case PLUGIN_WRITE: 59 | { 60 | String IrType; 61 | unsigned long IrCode; 62 | unsigned int IrBits; 63 | char command[80]; 64 | command[0] = 0; 65 | char TmpStr1[80]; 66 | TmpStr1[0] = 0; 67 | string.toCharArray(command, 80); 68 | 69 | String tmpString = string; 70 | int argIndex = tmpString.indexOf(','); 71 | if (argIndex) tmpString = tmpString.substring(0, argIndex); 72 | 73 | if (GetArgv(command, TmpStr1, 2)) IrType = TmpStr1; 74 | if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1 75 | if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1); 76 | 77 | if (tmpString.equalsIgnoreCase(F("IRSEND")) && Plugin_035_irSender != 0) 78 | { 79 | success = true; 80 | if (irReceiver != 0) irReceiver->disableIRIn(); // Stop the receiver 81 | 82 | if (IrType.equalsIgnoreCase(F("NEC"))) Plugin_035_irSender->sendNEC(IrCode, IrBits); 83 | if (IrType.equalsIgnoreCase(F("JVC"))) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2); 84 | if (IrType.equalsIgnoreCase(F("RC5"))) Plugin_035_irSender->sendRC5(IrCode, IrBits); 85 | if (IrType.equalsIgnoreCase(F("RC6"))) Plugin_035_irSender->sendRC6(IrCode, IrBits); 86 | if (IrType.equalsIgnoreCase(F("SAMSUNG"))) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits); 87 | if (IrType.equalsIgnoreCase(F("SONY"))) Plugin_035_irSender->sendSony(IrCode, IrBits); 88 | if (IrType.equalsIgnoreCase(F("PANASONIC"))) Plugin_035_irSender->sendPanasonic(IrBits, IrCode); 89 | 90 | String log = F("IRTX :IR Code Sent"); 91 | addLog(LOG_LEVEL_INFO, log); 92 | if (printToWeb) 93 | { 94 | printWebString += F("IR Code Sent "); 95 | printWebString += IrType; 96 | printWebString += F("
"); 97 | } 98 | 99 | if (irReceiver != 0) irReceiver->enableIRIn(); // Start the receiver 100 | } 101 | break; 102 | } 103 | } 104 | return success; 105 | } 106 | 107 | -------------------------------------------------------------------------------- /_P038_NeoPixel.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 038: NeoPixel Basic ####################################### 3 | //####################################################################################################### 4 | 5 | // Command: NeoPixel ,,, 6 | 7 | #include 8 | Adafruit_NeoPixel *Plugin_038_pixels; 9 | 10 | #define PLUGIN_038 11 | #define PLUGIN_ID_038 38 12 | #define PLUGIN_NAME_038 "NeoPixel - Basic" 13 | #define PLUGIN_VALUENAME1_038 "" 14 | boolean Plugin_038(byte function, struct EventStruct *event, String& string) 15 | { 16 | boolean success = false; 17 | 18 | switch (function) 19 | { 20 | 21 | case PLUGIN_DEVICE_ADD: 22 | { 23 | Device[++deviceCount].Number = PLUGIN_ID_038; 24 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 25 | Device[deviceCount].Custom = true; 26 | Device[deviceCount].TimerOption = false; 27 | break; 28 | } 29 | 30 | case PLUGIN_GET_DEVICENAME: 31 | { 32 | string = F(PLUGIN_NAME_038); 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICEVALUENAMES: 37 | { 38 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_038)); 39 | break; 40 | } 41 | 42 | case PLUGIN_WEBFORM_LOAD: 43 | { 44 | char tmpString[128]; 45 | sprintf_P(tmpString, PSTR("Led Count:"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 46 | string += tmpString; 47 | 48 | string += F("GPIO:"); 49 | addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]); 50 | 51 | success = true; 52 | break; 53 | } 54 | 55 | case PLUGIN_WEBFORM_SAVE: 56 | { 57 | String plugin1 = WebServer.arg(F("plugin_038_leds")); 58 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 59 | success = true; 60 | break; 61 | } 62 | 63 | case PLUGIN_INIT: 64 | { 65 | if (!Plugin_038_pixels) 66 | { 67 | Plugin_038_pixels = new Adafruit_NeoPixel(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePin1[event->TaskIndex], NEO_GRB + NEO_KHZ800); 68 | Plugin_038_pixels->begin(); // This initializes the NeoPixel library. 69 | } 70 | success = true; 71 | break; 72 | } 73 | 74 | case PLUGIN_WRITE: 75 | { 76 | if (Plugin_038_pixels) 77 | { 78 | String tmpString = string; 79 | int argIndex = tmpString.indexOf(','); 80 | if (argIndex) 81 | tmpString = tmpString.substring(0, argIndex); 82 | 83 | if (tmpString.equalsIgnoreCase(F("NeoPixel"))) 84 | { 85 | char Line[80]; 86 | char TmpStr1[80]; 87 | TmpStr1[0] = 0; 88 | string.toCharArray(Line, 80); 89 | int Par4 = 0; 90 | if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1); 91 | Plugin_038_pixels->setPixelColor(event->Par1 - 1, Plugin_038_pixels->Color(event->Par2, event->Par3, Par4)); 92 | Plugin_038_pixels->show(); // This sends the updated pixel color to the hardware. 93 | success = true; 94 | } 95 | } 96 | break; 97 | } 98 | 99 | } 100 | return success; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /_P040_ID12.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 040: Serial RFID ID-12 #################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_040 6 | #define PLUGIN_ID_040 40 7 | #define PLUGIN_NAME_040 "RFID Reader - ID12LA/RDM6300" 8 | #define PLUGIN_VALUENAME1_040 "Tag" 9 | 10 | boolean Plugin_040_init = false; 11 | 12 | boolean Plugin_040(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_040; 22 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 23 | Device[deviceCount].Ports = 0; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = false; 30 | Device[deviceCount].GlobalSyncOption = true; 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_040); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_040)); 43 | break; 44 | } 45 | 46 | 47 | case PLUGIN_INIT: 48 | { 49 | Plugin_040_init = true; 50 | Serial.begin(9600); 51 | success = true; 52 | break; 53 | } 54 | 55 | 56 | case PLUGIN_SERIAL_IN: 57 | { 58 | if (Plugin_040_init) 59 | { 60 | byte val = 0; 61 | byte code[6]; 62 | byte checksum = 0; 63 | byte bytesread = 0; 64 | byte tempbyte = 0; 65 | 66 | if ((val = Serial.read()) == 2) 67 | { // check for header 68 | bytesread = 0; 69 | while (bytesread < 12) { // read 10 digit code + 2 digit checksum 70 | if ( Serial.available() > 0) { 71 | val = Serial.read(); 72 | if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { 73 | // if header or stop bytes before the 10 digit reading 74 | break; 75 | } 76 | 77 | // Do Ascii/Hex conversion: 78 | if ((val >= '0') && (val <= '9')) { 79 | val = val - '0'; 80 | } 81 | else if ((val >= 'A') && (val <= 'F')) { 82 | val = 10 + val - 'A'; 83 | } 84 | 85 | // Every two hex-digits, add byte to code: 86 | if (bytesread & 1 == 1) { 87 | // make some space for this hex-digit by 88 | // shifting the previous hex-digit with 4 bits to the left: 89 | code[bytesread >> 1] = (val | (tempbyte << 4)); 90 | 91 | if (bytesread >> 1 != 5) { // If we're at the checksum byte, 92 | checksum ^= code[bytesread >> 1]; // Calculate the checksum... (XOR) 93 | }; 94 | } 95 | else { 96 | tempbyte = val; // Store the first hex digit first... 97 | }; 98 | bytesread++; // ready to read next digit 99 | } 100 | } 101 | } 102 | 103 | if (bytesread == 12) 104 | { 105 | if (code[5] == checksum) 106 | { 107 | // temp woraround, ESP Easy framework does not currently prepare this... 108 | byte index = 0; 109 | for (byte y = 0; y < TASKS_MAX; y++) 110 | if (Settings.TaskDeviceNumber[y] == PLUGIN_ID_040) 111 | index = y; 112 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[index]); 113 | event->TaskIndex = index; 114 | event->BaseVarIndex = index * VARS_PER_TASK; 115 | event->sensorType = Device[DeviceIndex].VType; 116 | // endof workaround 117 | 118 | unsigned long key = 0; 119 | for (byte i = 1; i < 5; i++) key = key | (((unsigned long) code[i] << ((4 - i) * 8))); 120 | UserVar[event->BaseVarIndex] = (key & 0xFFFF); 121 | UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); 122 | String log = F("RFID : Tag: "); 123 | log += key; 124 | addLog(LOG_LEVEL_INFO, log); 125 | sendData(event); 126 | } 127 | } 128 | success = true; 129 | } 130 | break; 131 | } 132 | 133 | } 134 | return success; 135 | } 136 | 137 | -------------------------------------------------------------------------------- /_P043_ClkOutput.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 043: Clock Output ######################################### 3 | //####################################################################################################### 4 | #define PLUGIN_043 5 | #define PLUGIN_ID_043 43 6 | #define PLUGIN_NAME_043 "Clock - Output" 7 | #define PLUGIN_VALUENAME1_043 "Output" 8 | #define PLUGIN_043_MAX_SETTINGS 8 9 | 10 | boolean Plugin_043(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | 14 | switch (function) 15 | { 16 | 17 | case PLUGIN_DEVICE_ADD: 18 | { 19 | Device[++deviceCount].Number = PLUGIN_ID_043; 20 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 21 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 22 | Device[deviceCount].Ports = 0; 23 | Device[deviceCount].PullUpOption = false; 24 | Device[deviceCount].InverseLogicOption = false; 25 | Device[deviceCount].FormulaOption = false; 26 | Device[deviceCount].ValueCount = 1; 27 | Device[deviceCount].SendDataOption = true; 28 | break; 29 | } 30 | 31 | case PLUGIN_GET_DEVICENAME: 32 | { 33 | string = F(PLUGIN_NAME_043); 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICEVALUENAMES: 38 | { 39 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_043)); 40 | break; 41 | } 42 | 43 | case PLUGIN_WEBFORM_LOAD: 44 | { 45 | for (byte x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) 46 | { 47 | string += F("Day,Time "); 48 | string += x+1; 49 | string += F(":"); 54 | 55 | byte choice = ExtraTaskSettings.TaskDevicePluginConfig[x]; 56 | String options[3]; 57 | options[0] = F(""); 58 | options[1] = F("Off"); 59 | options[2] = F("On"); 60 | int optionValues[3]; 61 | optionValues[0] = 0; 62 | optionValues[1] = 1; 63 | optionValues[2] = 2; 64 | string += F(""); 79 | } 80 | success = true; 81 | break; 82 | } 83 | 84 | case PLUGIN_WEBFORM_SAVE: 85 | { 86 | for (byte x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) 87 | { 88 | String argc = F("plugin_043_clock"); 89 | argc += x; 90 | String plugin1 = WebServer.arg(argc); 91 | ExtraTaskSettings.TaskDevicePluginConfigLong[x] = string2TimeLong(plugin1); 92 | 93 | argc = F("plugin_043_state"); 94 | argc += x; 95 | String plugin2 = WebServer.arg(argc); 96 | ExtraTaskSettings.TaskDevicePluginConfig[x] = plugin2.toInt(); 97 | } 98 | success = true; 99 | break; 100 | } 101 | 102 | case PLUGIN_INIT: 103 | { 104 | success = true; 105 | break; 106 | } 107 | 108 | case PLUGIN_CLOCK_IN: 109 | { 110 | LoadTaskSettings(event->TaskIndex); 111 | for (byte x = 0; x < PLUGIN_043_MAX_SETTINGS; x++) 112 | { 113 | unsigned long clockEvent = (unsigned long)minute() % 10 | (unsigned long)(minute() / 10) << 4 | (unsigned long)(hour() % 10) << 8 | (unsigned long)(hour() / 10) << 12 | (unsigned long)weekday() << 16; 114 | unsigned long clockSet = ExtraTaskSettings.TaskDevicePluginConfigLong[x]; 115 | 116 | if (matchClockEvent(clockEvent,clockSet)) 117 | { 118 | byte state = ExtraTaskSettings.TaskDevicePluginConfig[x]; 119 | if (state != 0) 120 | { 121 | state--; 122 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 123 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], state); 124 | UserVar[event->BaseVarIndex] = state; 125 | String log = F("TCLK : State "); 126 | log += state; 127 | addLog(LOG_LEVEL_INFO, log); 128 | sendData(event); 129 | } 130 | } 131 | } 132 | break; 133 | } 134 | } 135 | return success; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /__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 | -------------------------------------------------------------------------------- /__NPlugin.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Initialize all Controller NPlugins that where defined earlier 3 | // and initialize the function call pointer into the CNPlugin array 4 | //******************************************************************************** 5 | void NPluginInit(void) 6 | { 7 | byte x; 8 | 9 | // Clear pointer table for all plugins 10 | for (x = 0; x < NPLUGIN_MAX; x++) 11 | { 12 | NPlugin_ptr[x] = 0; 13 | NPlugin_id[x] = 0; 14 | } 15 | 16 | x = 0; 17 | 18 | #ifdef NPLUGIN_001 19 | NPlugin_id[x] = 1; NPlugin_ptr[x++] = &NPlugin_001; 20 | #endif 21 | 22 | #ifdef NPLUGIN_002 23 | NPlugin_id[x] = 2; NPlugin_ptr[x++] = &NPlugin_002; 24 | #endif 25 | 26 | #ifdef NPLUGIN_003 27 | NPlugin_id[x] = 3; NPlugin_ptr[x++] = &NPlugin_003; 28 | #endif 29 | 30 | #ifdef NPLUGIN_004 31 | NPlugin_id[x] = 4; NPlugin_ptr[x++] = &NPlugin_004; 32 | #endif 33 | 34 | #ifdef NPLUGIN_005 35 | NPlugin_id[x] = 5; NPlugin_ptr[x++] = &NPlugin_005; 36 | #endif 37 | 38 | #ifdef NPLUGIN_006 39 | NPlugin_id[x] = 6; NPlugin_ptr[x++] = &NPlugin_006; 40 | #endif 41 | 42 | #ifdef NPLUGIN_007 43 | NPlugin_id[x] = 7; NPlugin_ptr[x++] = &NPlugin_007; 44 | #endif 45 | 46 | #ifdef NPLUGIN_008 47 | NPlugin_id[x] = 8; NPlugin_ptr[x++] = &NPlugin_008; 48 | #endif 49 | 50 | #ifdef NPLUGIN_009 51 | NPlugin_id[x] = 9; NPlugin_ptr[x++] = &NPlugin_009; 52 | #endif 53 | 54 | #ifdef NPLUGIN_010 55 | NPlugin_id[x] = 10; NPlugin_ptr[x++] = &NPlugin_010; 56 | #endif 57 | 58 | #ifdef NPLUGIN_011 59 | NPlugin_id[x] = 11; NPlugin_ptr[x++] = &NPlugin_011; 60 | #endif 61 | 62 | #ifdef NPLUGIN_012 63 | NPlugin_id[x] = 12; NPlugin_ptr[x++] = &NPlugin_012; 64 | #endif 65 | 66 | #ifdef NPLUGIN_013 67 | NPlugin_id[x] = 13; NPlugin_ptr[x++] = &NPlugin_013; 68 | #endif 69 | 70 | #ifdef NPLUGIN_014 71 | NPlugin_id[x] = 14; NPlugin_ptr[x++] = &NPlugin_014; 72 | #endif 73 | 74 | #ifdef NPLUGIN_015 75 | NPlugin_id[x] = 15; NPlugin_ptr[x++] = &NPlugin_015; 76 | #endif 77 | 78 | #ifdef NPLUGIN_016 79 | NPlugin_id[x] = 16; NPlugin_ptr[x++] = &NPlugin_016; 80 | #endif 81 | 82 | #ifdef NPLUGIN_017 83 | NPlugin_id[x] = 17; NPlugin_ptr[x++] = &NPlugin_017; 84 | #endif 85 | 86 | #ifdef NPLUGIN_018 87 | NPlugin_id[x] = 18; NPlugin_ptr[x++] = &NPlugin_018; 88 | #endif 89 | 90 | #ifdef NPLUGIN_019 91 | NPlugin_id[x] = 19; NPlugin_ptr[x++] = &NPlugin_019; 92 | #endif 93 | 94 | #ifdef NPLUGIN_020 95 | NPlugin_id[x] = 20; NPlugin_ptr[x++] = &NPlugin_020; 96 | #endif 97 | 98 | #ifdef NPLUGIN_021 99 | NPlugin_id[x] = 21; NPlugin_ptr[x++] = &NPlugin_021; 100 | #endif 101 | 102 | #ifdef NPLUGIN_022 103 | NPlugin_id[x] = 22; NPlugin_ptr[x++] = &NPlugin_022; 104 | #endif 105 | 106 | #ifdef NPLUGIN_023 107 | NPlugin_id[x] = 23; NPlugin_ptr[x++] = &NPlugin_023; 108 | #endif 109 | 110 | #ifdef NPLUGIN_024 111 | NPlugin_id[x] = 24; NPlugin_ptr[x++] = &NPlugin_024; 112 | #endif 113 | 114 | #ifdef NPLUGIN_025 115 | NPlugin_id[x] = 25; NPlugin_ptr[x++] = &NPlugin_025; 116 | #endif 117 | 118 | NPluginCall(NPLUGIN_PROTOCOL_ADD, 0); 119 | } 120 | 121 | byte NPluginCall(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 NPLUGIN_PROTOCOL_ADD: 133 | for (x = 0; x < NPLUGIN_MAX; x++) 134 | if (NPlugin_id[x] != 0) 135 | NPlugin_ptr[x](Function, event, dummyString); 136 | return true; 137 | break; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | --------------------------------------------------------------------------------