├── Controller.ino ├── Hardware.ino ├── License.txt ├── MiniESPEasy.ino ├── MiniProExtender └── MiniProExtender.ino ├── Misc.ino ├── README.md ├── Serial.ino ├── WebServer.ino ├── Wifi.ino ├── _C001.ino ├── _C002.ino ├── _C003.ino ├── _C004.ino ├── _C005.ino ├── _C006.ino ├── _C007.ino ├── _C008.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 ├── __CPlugin.ino ├── __Plugin.ino └── __ReleaseNotes.ino /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.PinStates[x] != 0) 11 | switch(Settings.PinStates[x]) 12 | { 13 | case 1: 14 | pinMode(x,OUTPUT); 15 | digitalWrite(x,LOW); 16 | break; 17 | case 2: 18 | pinMode(x,OUTPUT); 19 | digitalWrite(x,HIGH); 20 | break; 21 | } 22 | 23 | // configure hardware pins according to eeprom settings. 24 | if (Settings.Pin_i2c_sda != -1) 25 | { 26 | String log = F("INIT : I2C"); 27 | addLog(LOG_LEVEL_INFO, log); 28 | Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl); 29 | } 30 | 31 | // I2C Watchdog boot status check 32 | if (Settings.WDI2CAddress != 0) 33 | { 34 | delay(500); 35 | Wire.beginTransmission(Settings.WDI2CAddress); 36 | Wire.write(0x83); // command to set pointer 37 | Wire.write(17); // pointer value to status byte 38 | Wire.endTransmission(); 39 | 40 | Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1); 41 | if (Wire.available()) 42 | { 43 | byte status = Wire.read(); 44 | if (status & 0x1) 45 | { 46 | String log = F("INIT : Reset by WD!"); 47 | addLog(LOG_LEVEL_ERROR, log); 48 | lastBootCause = BOOT_CAUSE_EXT_WD; 49 | } 50 | } 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /License.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/costonisp/MiniESPEasy/ab953054f1fcd368bf10b96005e7c47b5d939805/License.txt -------------------------------------------------------------------------------- /MiniProExtender/MiniProExtender.ino: -------------------------------------------------------------------------------- 1 | /****************************************************************************************************************************\ 2 | * Arduino project "ESP Easy" � Copyright www.esp8266.nu 3 | * 4 | * This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License 5 | * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 6 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 7 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 8 | * You received a copy of the GNU General Public License along with this program in file 'License.txt'. 9 | * 10 | * IDE download : https://www.arduino.cc/en/Main/Software 11 | * ESP8266 Package : https://github.com/esp8266/Arduino 12 | * 13 | * Source Code : https://sourceforge.net/projects/espeasy/ 14 | * Support : http://www.esp8266.nu 15 | * Discussion : http://www.esp8266.nu/forum/ 16 | * 17 | * Additional information about licensing can be found at : http://www.gnu.org/licenses 18 | \*************************************************************************************************************************/ 19 | 20 | // This file is to be loaded onto an Arduino Pro Mini so it will act as a simple IO extender to the ESP module. 21 | // Communication between ESP and Arduino is using the I2C bus, so only two wires needed. 22 | // It best to run the Pro Mini on 3V3, although the 16MHz versions do not officially support this voltage level on this frequency. 23 | // That way, you can skip levelconverters on I2C. 24 | // Arduino Mini Pro uses A4 and A5 for I2C bus. ESP I2C can be configured but they are on GPIO-4 and GPIO-5 by default. 25 | 26 | #include 27 | 28 | #define I2C_MSG_IN_SIZE 4 29 | #define I2C_MSG_OUT_SIZE 4 30 | 31 | #define CMD_DIGITAL_WRITE 1 32 | #define CMD_DIGITAL_READ 2 33 | #define CMD_ANALOG_WRITE 3 34 | #define CMD_ANALOG_READ 4 35 | 36 | volatile uint8_t sendBuffer[I2C_MSG_OUT_SIZE]; 37 | 38 | void setup() 39 | { 40 | Wire.begin(0x7f); 41 | Wire.onReceive(receiveEvent); 42 | Wire.onRequest(requestEvent); 43 | } 44 | 45 | void loop() {} 46 | 47 | void receiveEvent(int count) 48 | { 49 | if (count == I2C_MSG_IN_SIZE) 50 | { 51 | byte cmd = Wire.read(); 52 | byte port = Wire.read(); 53 | int value = Wire.read(); 54 | value += Wire.read()*256; 55 | switch(cmd) 56 | { 57 | case CMD_DIGITAL_WRITE: 58 | pinMode(port,OUTPUT); 59 | digitalWrite(port,value); 60 | break; 61 | case CMD_DIGITAL_READ: 62 | pinMode(port,INPUT_PULLUP); 63 | clearSendBuffer(); 64 | sendBuffer[0] = digitalRead(port); 65 | break; 66 | case CMD_ANALOG_WRITE: 67 | analogWrite(port,value); 68 | break; 69 | case CMD_ANALOG_READ: 70 | clearSendBuffer(); 71 | int valueRead = analogRead(port); 72 | sendBuffer[0] = valueRead & 0xff; 73 | sendBuffer[1] = valueRead >> 8; 74 | break; 75 | } 76 | } 77 | } 78 | 79 | void clearSendBuffer() 80 | { 81 | for(byte x=0; x < sizeof(sendBuffer); x++) 82 | sendBuffer[x]=0; 83 | } 84 | 85 | void requestEvent() 86 | { 87 | Wire.write((const uint8_t*)sendBuffer,sizeof(sendBuffer)); 88 | } 89 | 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MiniESPEasy is retired now because the functionality of enabling GPIO 1&3 is included in the beta versions of ESPEasy. 2 | ---------------------------------------------------------------------------------------------------------------------- 3 | 4 | MiniESPEasy = ESPEasy for modules with small number of available I/O pins 5 | 6 | This is a fork of stable ESPEasy-R78 release. 7 | Using this fork of ESPEasy you can use the Rxd and Txd pins on small modules like ESP-01, ESP-02 and several commercial WiFi-gadgeds with limited I/O pin numbers for general use and also for I2C use. 8 | 9 | For documentation of the program look at the documentation of ESPEasy 10 | 11 | If you are using MiniESPEasy for the first time, follow the instructions for installing ESPEasy on http://www.esp8266.nu/index.php/Main_Page. After installing the libraries use the Arduino IDE to compile the MiniESP sourcecode and flash your ESP8266. 12 | 13 | 14 | Wiki: http://www.esp8266.nu 15 | 16 | Forum: http://www.esp8266.nu/forum 17 | 18 | 19 | 20 | Credits: 21 | 22 | All credit for this program goes to the writer of ESPEasy Martinus (mvdbro). 23 | Also I want to mention martinayotte from the esp8266.com forum who alerted me to the existence of the Serial.swap() command. 24 | 25 | My work was only to add a few Serial.swap() commands, slightly change the Hardware page of the webGui so that GPIO-13&15 are replaced by GPIO-1&3, reordering the pin_list and adding GPIO-1&3 in the I2C selection menu. 26 | I also changed 2 bytes in the OLED module so that displays with SH1106 & SSD1366 controllers will be supported. 27 | -------------------------------------------------------------------------------- /Serial.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************************************\ 2 | * Process data from Serial Interface 3 | \*********************************************************************************************/ 4 | #define INPUT_COMMAND_SIZE 80 5 | void ExecuteCommand(const char *Line) 6 | { 7 | char TmpStr1[80]; 8 | TmpStr1[0] = 0; 9 | char Command[80]; 10 | Command[0] = 0; 11 | int Par1 = 0; 12 | int Par2 = 0; 13 | int Par3 = 0; 14 | 15 | GetArgv(Line, Command, 1); 16 | if (GetArgv(Line, TmpStr1, 2)) Par1 = str2int(TmpStr1); 17 | if (GetArgv(Line, TmpStr1, 3)) Par2 = str2int(TmpStr1); 18 | if (GetArgv(Line, TmpStr1, 4)) Par3 = str2int(TmpStr1); 19 | 20 | // **************************************** 21 | // commands for debugging 22 | // **************************************** 23 | 24 | 25 | if (strcasecmp_P(Command, PSTR("TaskClear")) == 0) 26 | { 27 | taskClear(Par1 - 1,true); 28 | } 29 | 30 | if (strcasecmp_P(Command, PSTR("wdconfig")) == 0) 31 | { 32 | Wire.beginTransmission(Par1); // address 33 | Wire.write(Par2); // command 34 | Wire.write(Par3); // data 35 | Wire.endTransmission(); 36 | } 37 | 38 | if (strcasecmp_P(Command, PSTR("wdread")) == 0) 39 | { 40 | Wire.beginTransmission(Par1); // address 41 | Wire.write(0x83); // command to set pointer 42 | Wire.write(Par2); // pointer value 43 | Wire.endTransmission(); 44 | Wire.requestFrom((uint8_t)Par1, (uint8_t)1); 45 | if (Wire.available()) 46 | { 47 | byte value = Wire.read(); 48 | if(printToWeb) 49 | { 50 | printWebString += F("Reg value: "); 51 | printWebString += value; 52 | } 53 | Serial.print(F("Reg value: ")); 54 | Serial.println(value); 55 | } 56 | } 57 | 58 | if (strcasecmp_P(Command, PSTR("VariableSet")) == 0) 59 | { 60 | if (GetArgv(Line, TmpStr1, 3)) 61 | UserVar[Par1 - 1] = atof(TmpStr1); 62 | } 63 | 64 | if (strcasecmp_P(Command, PSTR("build")) == 0) 65 | { 66 | Settings.Build = Par1; 67 | SaveSettings(); 68 | } 69 | 70 | if (strcasecmp_P(Command, PSTR("NoSleep")) == 0) 71 | { 72 | Settings.deepSleep = 0; 73 | } 74 | 75 | // **************************************** 76 | // special commands for old nodo plugin 77 | // **************************************** 78 | 79 | if (strcasecmp_P(Command, PSTR("DomoticzSend")) == 0) 80 | { 81 | if (GetArgv(Line, TmpStr1, 4)) 82 | { 83 | struct EventStruct TempEvent; 84 | TempEvent.TaskIndex = 0; 85 | TempEvent.BaseVarIndex = (VARS_PER_TASK * TASKS_MAX) - 1; 86 | TempEvent.idx = Par2; 87 | TempEvent.sensorType = Par1; 88 | UserVar[(VARS_PER_TASK * TASKS_MAX) - 1] = atof(TmpStr1); 89 | sendData(&TempEvent); 90 | } 91 | } 92 | 93 | if (strcasecmp(Command, "DomoticzGet") == 0) 94 | { 95 | float value = 0; 96 | if (Domoticz_getData(Par2, &value)) 97 | { 98 | Serial.print("DomoticzGet "); 99 | Serial.println(value); 100 | } 101 | else 102 | Serial.println("Error getting data"); 103 | } 104 | 105 | // **************************************** 106 | // configure settings commands 107 | // **************************************** 108 | if (strcasecmp_P(Command, PSTR("WifiSSID")) == 0) 109 | strcpy(SecuritySettings.WifiSSID, Line + 9); 110 | 111 | if (strcasecmp_P(Command, PSTR("WifiKey")) == 0) 112 | strcpy(SecuritySettings.WifiKey, Line + 8); 113 | 114 | if (strcasecmp_P(Command, PSTR("WifiScan")) == 0) 115 | WifiScan(); 116 | 117 | if (strcasecmp_P(Command, PSTR("WifiConnect")) == 0) 118 | WifiConnect(); 119 | 120 | if (strcasecmp_P(Command, PSTR("WifiDisconnect")) == 0) 121 | WifiDisconnect(); 122 | 123 | if (strcasecmp_P(Command, PSTR("Reboot")) == 0) 124 | { 125 | pinMode(0, INPUT); 126 | pinMode(2, INPUT); 127 | pinMode(15, INPUT); 128 | ESP.reset(); 129 | } 130 | 131 | if (strcasecmp_P(Command, PSTR("Restart")) == 0) 132 | ESP.restart(); 133 | 134 | if (strcasecmp_P(Command, PSTR("Erase")) == 0) 135 | { 136 | EraseFlash(); 137 | ZeroFillFlash(); 138 | saveToRTC(0); 139 | WiFi.persistent(true); // use SDK storage of SSID/WPA parameters 140 | WiFi.disconnect(); // this will store empty ssid/wpa into sdk storage 141 | WiFi.persistent(false); // Do not use SDK storage of SSID/WPA parameters 142 | } 143 | 144 | if (strcasecmp_P(Command, PSTR("Reset")) == 0) 145 | ResetFactory(); 146 | 147 | if (strcasecmp_P(Command, PSTR("Save")) == 0) 148 | SaveSettings(); 149 | 150 | if (strcasecmp_P(Command, PSTR("Load")) == 0) 151 | LoadSettings(); 152 | 153 | if (strcasecmp_P(Command, PSTR("FlashDump")) == 0) 154 | { 155 | uint32_t _sectorStart = ((uint32_t)&_SPIFFS_start - 0x40200000) / SPI_FLASH_SEC_SIZE; 156 | uint32_t _sectorEnd = ((uint32_t)&_SPIFFS_end - 0x40200000) / SPI_FLASH_SEC_SIZE; 157 | 158 | Serial.print(F("Sketch size : ")); 159 | Serial.println(ESP.getSketchSize()); 160 | Serial.print(F("Sketch free space : ")); 161 | Serial.println(ESP.getFreeSketchSpace()); 162 | Serial.print(F("Flash size : ")); 163 | Serial.println(ESP.getFlashChipRealSize()); 164 | Serial.print(F("SPIFFS start sector: ")); 165 | Serial.println(_sectorStart); 166 | Serial.print(F("SPIFFS end sector : ")); 167 | Serial.println(_sectorEnd); 168 | char data[80]; 169 | if (Par2 == 0) Par2 = Par1; 170 | for (int x = Par1; x <= Par2; x++) 171 | { 172 | LoadFromFlash(x * 1024, (byte*)&data, sizeof(data)); 173 | Serial.print(F("Offset: ")); 174 | Serial.print(x); 175 | Serial.print(" : "); 176 | Serial.println(data); 177 | } 178 | } 179 | 180 | if (strcasecmp_P(Command, PSTR("flashcheck")) == 0) 181 | { 182 | CheckFlash(Par1, Par2); 183 | } 184 | 185 | if (strcasecmp_P(Command, PSTR("Delay")) == 0) 186 | Settings.Delay = Par1; 187 | 188 | if (strcasecmp_P(Command, PSTR("Debug")) == 0) 189 | Settings.SerialLogLevel = Par1; 190 | 191 | if (strcasecmp_P(Command, PSTR("IP")) == 0) 192 | { 193 | if (GetArgv(Line, TmpStr1, 2)) 194 | if (!str2ip(TmpStr1, Settings.IP)) 195 | Serial.println("?"); 196 | } 197 | 198 | if (strcasecmp_P(Command, PSTR("Settings")) == 0) 199 | { 200 | char str[20]; 201 | Serial.println(); 202 | 203 | Serial.println(F("System Info")); 204 | IPAddress ip = WiFi.localIP(); 205 | sprintf_P(str, PSTR("%u.%u.%u.%u"), ip[0], ip[1], ip[2], ip[3]); 206 | Serial.print(F(" IP Address : ")); Serial.println(str); 207 | Serial.print(F(" Build : ")); Serial.println((int)BUILD); 208 | Serial.print(F(" Unit : ")); Serial.println((int)Settings.Unit); 209 | Serial.print(F(" WifiSSID : ")); Serial.println(SecuritySettings.WifiSSID); 210 | Serial.print(F(" WifiKey : ")); Serial.println(SecuritySettings.WifiKey); 211 | Serial.print(F(" Free mem : ")); Serial.println(FreeMem()); 212 | } 213 | } 214 | 215 | 216 | /********************************************************************************************\ 217 | * Get data from Serial Interface 218 | \*********************************************************************************************/ 219 | #define INPUT_BUFFER_SIZE 128 220 | 221 | byte SerialInByte; 222 | int SerialInByteCounter = 0; 223 | char InputBuffer_Serial[INPUT_BUFFER_SIZE + 2]; 224 | 225 | void serial() 226 | { 227 | while (Serial.available()) 228 | { 229 | yield(); 230 | SerialInByte = Serial.read(); 231 | if (SerialInByte == 255) // binary data... 232 | { 233 | Serial.flush(); 234 | return; 235 | } 236 | 237 | if (isprint(SerialInByte)) 238 | { 239 | if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits 240 | InputBuffer_Serial[SerialInByteCounter++] = SerialInByte; 241 | } 242 | 243 | if (SerialInByte == '\n') 244 | { 245 | InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed 246 | Serial.write('>'); 247 | Serial.println(InputBuffer_Serial); 248 | ExecuteCommand(InputBuffer_Serial); 249 | SerialInByteCounter = 0; 250 | InputBuffer_Serial[0] = 0; // serial data processed, clear buffer 251 | } 252 | } 253 | } 254 | 255 | -------------------------------------------------------------------------------- /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 | char ap_ssid[20]; 27 | ap_ssid[0] = 0; 28 | strcpy(ap_ssid, "ESP_"); 29 | sprintf_P(ap_ssid, PSTR("%s%u"), ap_ssid, Settings.Unit); 30 | WiFi.softAP(ap_ssid, SecuritySettings.WifiAPKey); 31 | WiFi.mode(WIFI_AP_STA); 32 | } 33 | else 34 | { 35 | AP_Mode = false; 36 | WiFi.mode(WIFI_STA); 37 | } 38 | } 39 | 40 | 41 | //******************************************************************************** 42 | // Connect to Wifi AP 43 | //******************************************************************************** 44 | boolean WifiConnect() 45 | { 46 | String log = ""; 47 | byte connectAttempts = 3; 48 | if (wifiSetup) 49 | connectAttempts = 1; 50 | 51 | char hostName[sizeof(Settings.Name)]; 52 | strcpy(hostName,Settings.Name); 53 | for(byte x=0; x< sizeof(hostName); x++) 54 | if (hostName[x] == ' ') 55 | hostName[x] = '-'; 56 | wifi_station_set_hostname(hostName); 57 | 58 | if (Settings.IP[0] != 0 && Settings.IP[0] != 255) 59 | { 60 | char str[20]; 61 | sprintf_P(str, PSTR("%u.%u.%u.%u"), Settings.IP[0], Settings.IP[1], Settings.IP[2], Settings.IP[3]); 62 | log = F("IP : Static IP :"); 63 | log += str; 64 | addLog(LOG_LEVEL_INFO, log); 65 | IPAddress ip = Settings.IP; 66 | IPAddress gw = Settings.Gateway; 67 | IPAddress subnet = Settings.Subnet; 68 | IPAddress dns = Settings.DNS; 69 | WiFi.config(ip, gw, subnet, dns); 70 | } 71 | 72 | 73 | if (WiFi.status() != WL_CONNECTED) 74 | { 75 | if ((SecuritySettings.WifiSSID[0] != 0) && (strcasecmp(SecuritySettings.WifiSSID, "ssid") != 0)) 76 | { 77 | for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++) 78 | { 79 | log = F("WIFI : Connecting... "); 80 | log += tryConnect; 81 | addLog(LOG_LEVEL_INFO, log); 82 | 83 | if (tryConnect == 1) 84 | WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey); 85 | else 86 | WiFi.begin(); 87 | 88 | for (byte x = 0; x < 20; x++) 89 | { 90 | if (WiFi.status() != WL_CONNECTED) 91 | { 92 | delay(500); 93 | } 94 | else 95 | break; 96 | } 97 | if (WiFi.status() == WL_CONNECTED) 98 | { 99 | log = F("WIFI : Connected!"); 100 | addLog(LOG_LEVEL_INFO, log); 101 | break; 102 | } 103 | else 104 | { 105 | log = F("WIFI : Disconnecting!"); 106 | addLog(LOG_LEVEL_INFO, log); 107 | ETS_UART_INTR_DISABLE(); 108 | wifi_station_disconnect(); 109 | ETS_UART_INTR_ENABLE(); 110 | delay(1000); 111 | } 112 | } 113 | 114 | // fix ip if last octet is set 115 | if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255) 116 | { 117 | IPAddress ip = WiFi.localIP(); 118 | IPAddress gw = WiFi.gatewayIP(); 119 | IPAddress subnet = WiFi.subnetMask(); 120 | ip[3] = Settings.IP_Octet; 121 | log = F("IP : Fixed IP :"); 122 | log += ip; 123 | addLog(LOG_LEVEL_INFO, log); 124 | WiFi.config(ip, gw, subnet); 125 | } 126 | } 127 | else 128 | { 129 | log = F("WIFI : No SSID!"); 130 | addLog(LOG_LEVEL_INFO, log); 131 | NC_Count = 1; 132 | WifiAPMode(true); 133 | } 134 | } 135 | } 136 | 137 | 138 | //******************************************************************************** 139 | // Disconnect from Wifi AP 140 | //******************************************************************************** 141 | boolean WifiDisconnect() 142 | { 143 | WiFi.disconnect(); 144 | } 145 | 146 | 147 | //******************************************************************************** 148 | // Scan all Wifi Access Points 149 | //******************************************************************************** 150 | void WifiScan() 151 | { 152 | // Direct Serial is allowed here, since this function will only be called from serial input. 153 | Serial.println(F("WIFI : SSID Scan start")); 154 | int n = WiFi.scanNetworks(); 155 | if (n == 0) 156 | Serial.println(F("WIFI : No networks found")); 157 | else 158 | { 159 | Serial.print(F("WIFI : ")); 160 | Serial.print(n); 161 | Serial.println(F(" networks found")); 162 | for (int i = 0; i < n; ++i) 163 | { 164 | // Print SSID and RSSI for each network found 165 | Serial.print(F("WIFI : ")); 166 | Serial.print(i + 1); 167 | Serial.print(": "); 168 | Serial.print(WiFi.SSID(i)); 169 | Serial.print(" ("); 170 | Serial.print(WiFi.RSSI(i)); 171 | Serial.print(")"); 172 | Serial.println(""); 173 | delay(10); 174 | } 175 | } 176 | Serial.println(""); 177 | } 178 | 179 | 180 | //******************************************************************************** 181 | // Check if we are still connected to a Wifi AP 182 | //******************************************************************************** 183 | void WifiCheck() 184 | { 185 | if(wifiSetup) 186 | return; 187 | 188 | if (WiFi.status() != WL_CONNECTED) 189 | { 190 | NC_Count++; 191 | if (NC_Count > 10 && !AP_Mode) 192 | { 193 | C_Count = 0; 194 | WifiAPMode(true); 195 | } 196 | } 197 | else 198 | { 199 | C_Count++; 200 | NC_Count = 0; 201 | if (C_Count > 60) 202 | { 203 | byte wifimode = wifi_get_opmode(); 204 | if (wifimode == 2 || wifimode == 3) //apmode is active 205 | { 206 | WifiAPMode(false); 207 | } 208 | } 209 | } 210 | } 211 | 212 | -------------------------------------------------------------------------------- /_C001.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 001: Domoticz HTTP ###################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_001 6 | #define CPLUGIN_ID_001 1 7 | #define CPLUGIN_NAME_001 "Domoticz HTTP" 8 | 9 | boolean CPlugin_001(byte function, struct EventStruct *event) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_001; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_001)); 19 | Protocol[protocolCount].usesMQTT = false; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 8080; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_SEND: 27 | { 28 | char log[80]; 29 | boolean success = false; 30 | char host[20]; 31 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 32 | 33 | sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host); 34 | addLog(LOG_LEVEL_DEBUG, log); 35 | if (printToWeb) 36 | { 37 | printWebString += log; 38 | printWebString += "
"; 39 | } 40 | // Use WiFiClient class to create TCP connections 41 | WiFiClient client; 42 | if (!client.connect(host, Settings.ControllerPort)) 43 | { 44 | connectionFailures++; 45 | strcpy_P(log, PSTR("HTTP : connection failed")); 46 | addLog(LOG_LEVEL_ERROR, log); 47 | if (printToWeb) 48 | printWebString += F("connection failed
"); 49 | return false; 50 | } 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | // We now create a URI for the request 55 | String url = F("/json.htm?type=command¶m=udevice&idx="); 56 | url += event->idx; 57 | 58 | switch (event->sensorType) 59 | { 60 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 61 | url += F("&svalue="); 62 | url += UserVar[event->BaseVarIndex]; 63 | break; 64 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 65 | url += F("&svalue="); 66 | url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 67 | break; 68 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 69 | url += F("&svalue="); 70 | url += UserVar[event->BaseVarIndex]; 71 | url += ";"; 72 | url += UserVar[event->BaseVarIndex + 1]; 73 | url += ";0"; 74 | break; 75 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 76 | url += F("&svalue="); 77 | url += UserVar[event->BaseVarIndex]; 78 | url += ";0;0;"; 79 | url += UserVar[event->BaseVarIndex + 1]; 80 | url += ";0"; 81 | break; 82 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 83 | url += F("&svalue="); 84 | url += UserVar[event->BaseVarIndex]; 85 | url += ";"; 86 | url += UserVar[event->BaseVarIndex + 1]; 87 | url += ";0;"; 88 | url += UserVar[event->BaseVarIndex + 2]; 89 | url += ";0"; 90 | break; 91 | case SENSOR_TYPE_SWITCH: 92 | url = F("/json.htm?type=command¶m=switchlight&idx="); 93 | url += event->idx; 94 | url += F("&switchcmd="); 95 | if (UserVar[event->BaseVarIndex] == 0) 96 | url += "Off"; 97 | else 98 | url += "On"; 99 | break; 100 | case SENSOR_TYPE_DIMMER: 101 | url = F("/json.htm?type=command¶m=switchlight&idx="); 102 | url += event->idx; 103 | url += F("&switchcmd="); 104 | if (UserVar[event->BaseVarIndex] == 0) 105 | url += "Off"; 106 | else 107 | { 108 | url += F("Set%20Level&level="); 109 | url += UserVar[event->BaseVarIndex]; 110 | } 111 | break; 112 | } 113 | 114 | url.toCharArray(log, 80); 115 | addLog(LOG_LEVEL_DEBUG_MORE, log); 116 | if (printToWeb) 117 | { 118 | printWebString += log; 119 | printWebString += "
"; 120 | } 121 | 122 | // This will send the request to the server 123 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 124 | "Host: " + host + "\r\n" + 125 | "Connection: close\r\n\r\n"); 126 | 127 | unsigned long timer = millis() + 200; 128 | while (!client.available() && millis() < timer) 129 | delay(1); 130 | 131 | // Read all the lines of the reply from server and print them to Serial 132 | while (client.available()) { 133 | String line = client.readStringUntil('\n'); 134 | line.toCharArray(log, 80); 135 | addLog(LOG_LEVEL_DEBUG_MORE, log); 136 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 137 | { 138 | strcpy_P(log, PSTR("HTTP : Succes!")); 139 | addLog(LOG_LEVEL_DEBUG, log); 140 | if (printToWeb) 141 | printWebString += F("Success
"); 142 | success = true; 143 | } 144 | delay(1); 145 | } 146 | strcpy_P(log, PSTR("HTTP : closing connection")); 147 | addLog(LOG_LEVEL_DEBUG, log); 148 | if (printToWeb) 149 | printWebString += F("closing connection
"); 150 | 151 | client.flush(); 152 | client.stop(); 153 | 154 | break; 155 | } 156 | 157 | } 158 | return success; 159 | } 160 | 161 | boolean Domoticz_getData(int idx, float *data) 162 | { 163 | boolean success = false; 164 | char host[20]; 165 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 166 | 167 | // Use WiFiClient class to create TCP connections 168 | WiFiClient client; 169 | if (!client.connect(host, Settings.ControllerPort)) 170 | { 171 | connectionFailures++; 172 | return false; 173 | } 174 | if (connectionFailures) 175 | connectionFailures--; 176 | 177 | // We now create a URI for the request 178 | String url = F("/json.htm?type=devices&rid="); 179 | url += idx; 180 | 181 | // This will send the request to the server 182 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 183 | "Host: " + host + "\r\n" + 184 | "Connection: close\r\n\r\n"); 185 | 186 | unsigned long timer = millis() + 200; 187 | while (!client.available() && millis() < timer) 188 | delay(1); 189 | 190 | // Read all the lines of the reply from server and print them to Serial 191 | 192 | while (client.available()) { 193 | String line = client.readStringUntil('\n'); 194 | if (line.substring(10, 14) == "Data") 195 | { 196 | String strValue = line.substring(19); 197 | byte pos = strValue.indexOf(' '); 198 | strValue = strValue.substring(0, pos); 199 | strValue.trim(); 200 | float value = strValue.toFloat(); 201 | *data = value; 202 | success = true; 203 | } 204 | } 205 | return success; 206 | } 207 | 208 | 209 | -------------------------------------------------------------------------------- /_C002.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 002: Domoticz MQTT ###################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_002 6 | #define CPLUGIN_ID_002 2 7 | #define CPLUGIN_NAME_002 "Domoticz MQTT" 8 | 9 | boolean CPlugin_002(byte function, struct EventStruct *event) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_002; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_002)); 19 | Protocol[protocolCount].usesMQTT = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_TEMPLATE: 27 | { 28 | strcpy_P(Settings.MQTTsubscribe, PSTR("domoticz/out")); 29 | strcpy_P(Settings.MQTTpublish, PSTR("domoticz/in")); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_RECV: 34 | { 35 | char json[512]; 36 | json[0] = 0; 37 | event->String2.toCharArray(json, 512); 38 | 39 | StaticJsonBuffer<512> jsonBuffer; 40 | JsonObject& root = jsonBuffer.parseObject(json); 41 | 42 | if (root.success()) 43 | { 44 | long idx = root["idx"]; 45 | float nvalue = root["nvalue"]; 46 | long nvaluealt = root["nvalue"]; 47 | const char* name = root["name"]; 48 | const char* svalue = root["svalue"]; 49 | const char* svalue1 = root["svalue1"]; 50 | const char* svalue2 = root["svalue2"]; 51 | const char* svalue3 = root["svalue3"]; 52 | 53 | if (nvalue == 0) 54 | nvalue = nvaluealt; 55 | 56 | // Direct Serial is allowed here, since this is still in development, it does not even work.... 57 | 58 | Serial.print(F("MQTT : idx=")); 59 | Serial.print(idx); 60 | Serial.print(F(" name=")); 61 | Serial.print(name); 62 | Serial.print(F(" nvalue=")); 63 | Serial.print(nvalue); 64 | Serial.print(F(" svalue=")); 65 | Serial.print(svalue); 66 | Serial.print(F(" svalue1=")); 67 | Serial.print(svalue1); 68 | Serial.print(F(" svalue2=")); 69 | Serial.println(svalue2); 70 | Serial.print(F(" svalue3=")); 71 | Serial.println(svalue3); 72 | } 73 | else 74 | Serial.println(F("MQTT : json parse error")); 75 | break; 76 | } 77 | 78 | case CPLUGIN_PROTOCOL_SEND: 79 | { 80 | StaticJsonBuffer<200> jsonBuffer; 81 | 82 | JsonObject& root = jsonBuffer.createObject(); 83 | 84 | root["idx"] = event->idx; 85 | 86 | String values; 87 | char str[80]; 88 | 89 | switch (event->sensorType) 90 | { 91 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 92 | root["nvalue"] = 0; 93 | values = UserVar[event->BaseVarIndex]; 94 | values.toCharArray(str, 80); 95 | root["svalue"] = str; 96 | break; 97 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 98 | root["nvalue"] = 0; 99 | values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 100 | values.toCharArray(str, 80); 101 | root["svalue"] = str; 102 | break; 103 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 104 | root["nvalue"] = 0; 105 | values = UserVar[event->BaseVarIndex]; 106 | values += ";"; 107 | values += UserVar[event->BaseVarIndex + 1]; 108 | values += ";0"; 109 | values.toCharArray(str, 80); 110 | root["svalue"] = str; 111 | break; 112 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 113 | root["nvalue"] = 0; 114 | values = UserVar[event->BaseVarIndex]; 115 | values += ";0;0;"; 116 | values += UserVar[event->BaseVarIndex + 1]; 117 | values += ";0"; 118 | values.toCharArray(str, 80); 119 | root["svalue"] = str; 120 | break; 121 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 122 | root["nvalue"] = 0; 123 | values = UserVar[event->BaseVarIndex]; 124 | values += ";"; 125 | values += UserVar[event->BaseVarIndex + 1]; 126 | values += ";0;"; 127 | values += UserVar[event->BaseVarIndex + 2]; 128 | values += ";0"; 129 | values.toCharArray(str, 80); 130 | root["svalue"] = str; 131 | break; 132 | case SENSOR_TYPE_SWITCH: 133 | root["command"] = "switchlight"; 134 | if (UserVar[event->BaseVarIndex] == 0) 135 | root["switchcmd"] = "Off"; 136 | else 137 | root["switchcmd"] = "On"; 138 | break; 139 | case SENSOR_TYPE_DIMMER: 140 | root["command"] = "switchlight"; 141 | if (UserVar[event->BaseVarIndex] == 0) 142 | root["switchcmd"] = "Off"; 143 | else 144 | root["Set%20Level"] = UserVar[event->BaseVarIndex]; 145 | break; 146 | } 147 | 148 | char json[256]; 149 | root.printTo(json, sizeof(json)); 150 | String log = F("MQTT : "); 151 | log += json; 152 | addLog(LOG_LEVEL_DEBUG, json); 153 | 154 | String pubname = Settings.MQTTpublish; 155 | pubname.replace("%sysname%", Settings.Name); 156 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 157 | pubname.replace("%id%", String(event->idx)); 158 | 159 | if (!MQTTclient.publish(pubname, json)) 160 | { 161 | log = F("MQTT publish failed"); 162 | addLog(LOG_LEVEL_DEBUG, json); 163 | MQTTConnect(); 164 | connectionFailures++; 165 | } 166 | else if (connectionFailures) 167 | connectionFailures--; 168 | break; 169 | } 170 | 171 | } 172 | return success; 173 | } 174 | 175 | -------------------------------------------------------------------------------- /_C003.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) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_003; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_003)); 19 | Protocol[protocolCount].usesMQTT = false; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 23; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_SEND: 27 | { 28 | char log[80]; 29 | boolean success = false; 30 | char host[20]; 31 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 32 | 33 | sprintf_P(log, PSTR("%s%s"), "TELNT: connecting to ", host); 34 | addLog(LOG_LEVEL_DEBUG, log); 35 | if (printToWeb) 36 | { 37 | printWebString += log; 38 | printWebString += "
"; 39 | } 40 | // Use WiFiClient class to create TCP connections 41 | WiFiClient client; 42 | if (!client.connect(host, Settings.ControllerPort)) 43 | { 44 | connectionFailures++; 45 | strcpy_P(log, PSTR("TELNT: connection failed")); 46 | addLog(LOG_LEVEL_ERROR, log); 47 | if (printToWeb) 48 | printWebString += F("connection failed
"); 49 | return false; 50 | } 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | float value = UserVar[event->BaseVarIndex]; 55 | // We now create a URI for the request 56 | String url = F("variableset "); 57 | url += event->idx; 58 | url += ","; 59 | url += value; 60 | url += "\n"; 61 | 62 | strcpy_P(log, PSTR("TELNT: Sending enter")); 63 | addLog(LOG_LEVEL_ERROR, log); 64 | client.print(" \n"); 65 | 66 | unsigned long timer = millis() + 200; 67 | while (!client.available() && millis() < timer) 68 | delay(1); 69 | 70 | timer = millis() + 1000; 71 | while (client.available() && millis() < timer && !success) 72 | { 73 | String line = client.readStringUntil('\n'); 74 | //Serial.println(line); 75 | if (line.substring(0, 20) == "Enter your password:") 76 | { 77 | success = true; 78 | strcpy_P(log, PSTR("TELNT: Password request ok")); 79 | addLog(LOG_LEVEL_ERROR, log); 80 | } 81 | delay(1); 82 | } 83 | 84 | strcpy_P(log, PSTR("TELNT: Sending pw")); 85 | addLog(LOG_LEVEL_ERROR, log); 86 | client.println(SecuritySettings.ControllerPassword); 87 | delay(100); 88 | while (client.available()) 89 | client.read(); 90 | 91 | strcpy_P(log, PSTR("TELNT: Sending cmd")); 92 | addLog(LOG_LEVEL_ERROR, log); 93 | client.print(url); 94 | delay(10); 95 | while (client.available()) 96 | client.read(); 97 | 98 | strcpy_P(log, PSTR("TELNT: closing connection")); 99 | addLog(LOG_LEVEL_DEBUG, log); 100 | if (printToWeb) 101 | printWebString += F("closing connection
"); 102 | 103 | client.stop(); 104 | 105 | break; 106 | } 107 | 108 | } 109 | return success; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /_C004.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) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_004; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_004)); 19 | Protocol[protocolCount].usesMQTT = false; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 80; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_SEND: 27 | { 28 | char log[80]; 29 | boolean success = false; 30 | char host[20]; 31 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 32 | 33 | sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host); 34 | addLog(LOG_LEVEL_DEBUG, log); 35 | if (printToWeb) 36 | { 37 | printWebString += log; 38 | printWebString += "
"; 39 | } 40 | // Use WiFiClient class to create TCP connections 41 | WiFiClient client; 42 | if (!client.connect(host, Settings.ControllerPort)) 43 | { 44 | connectionFailures++; 45 | strcpy_P(log, PSTR("HTTP : connection failed")); 46 | addLog(LOG_LEVEL_ERROR, log); 47 | if (printToWeb) 48 | printWebString += F("connection failed
"); 49 | return false; 50 | } 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | String postDataStr = SecuritySettings.ControllerPassword; // "0UDNN17RW6XAS2E5" // api key 55 | 56 | switch (event->sensorType) 57 | { 58 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 59 | case SENSOR_TYPE_SWITCH: 60 | postDataStr += F("&field"); 61 | postDataStr += event->idx; 62 | postDataStr += "="; 63 | postDataStr += String(UserVar[event->BaseVarIndex]); 64 | break; 65 | case SENSOR_TYPE_TEMP_HUM: // dual value 66 | case SENSOR_TYPE_TEMP_BARO: 67 | postDataStr += F("&field"); 68 | postDataStr += event->idx; 69 | postDataStr += "="; 70 | postDataStr += String(UserVar[event->BaseVarIndex]); 71 | postDataStr += F("&field"); 72 | postDataStr += event->idx + 1; 73 | postDataStr += "="; 74 | postDataStr += String(UserVar[event->BaseVarIndex + 1]); 75 | break; 76 | case SENSOR_TYPE_TEMP_HUM_BARO: 77 | postDataStr += F("&field"); 78 | postDataStr += event->idx; 79 | postDataStr += "="; 80 | postDataStr += String(UserVar[event->BaseVarIndex]); 81 | postDataStr += F("&field"); 82 | postDataStr += event->idx + 1; 83 | postDataStr += "="; 84 | postDataStr += String(UserVar[event->BaseVarIndex + 1]); 85 | postDataStr += F("&field"); 86 | postDataStr += event->idx + 2; 87 | postDataStr += "="; 88 | postDataStr += String(UserVar[event->BaseVarIndex + 2]); 89 | break; 90 | } 91 | postDataStr += F("\r\n\r\n"); 92 | 93 | String postStr = F("POST /update HTTP/1.1\n"); 94 | postStr += F("Host: api.thingspeak.com\n"); 95 | postStr += F("Connection: close\n"); 96 | postStr += F("X-THINGSPEAKAPIKEY: "); 97 | postStr += SecuritySettings.ControllerPassword; 98 | postStr += "\n"; 99 | postStr += F("Content-Type: application/x-www-form-urlencoded\n"); 100 | postStr += F("Content-Length: "); 101 | postStr += postDataStr.length(); 102 | postStr += F("\n\n"); 103 | postStr += postDataStr; 104 | 105 | // This will send the request to the server 106 | client.print(postStr); 107 | 108 | unsigned long timer = millis() + 200; 109 | while (!client.available() && millis() < timer) 110 | delay(1); 111 | 112 | // Read all the lines of the reply from server and print them to Serial 113 | while (client.available()) { 114 | String line = client.readStringUntil('\n'); 115 | line.toCharArray(log, 80); 116 | addLog(LOG_LEVEL_DEBUG_MORE, log); 117 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 118 | { 119 | strcpy_P(log, PSTR("HTTP : Succes!")); 120 | addLog(LOG_LEVEL_DEBUG, log); 121 | if (printToWeb) 122 | printWebString += F("Success
"); 123 | success = true; 124 | } 125 | delay(1); 126 | } 127 | strcpy_P(log, PSTR("HTTP : closing connection")); 128 | addLog(LOG_LEVEL_DEBUG, log); 129 | if (printToWeb) 130 | printWebString += F("closing connection
"); 131 | 132 | client.flush(); 133 | client.stop(); 134 | break; 135 | } 136 | 137 | } 138 | return success; 139 | } 140 | 141 | -------------------------------------------------------------------------------- /_C005.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 005: OpenHAB MQTT ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_005 6 | #define CPLUGIN_ID_005 5 7 | #define CPLUGIN_NAME_005 "OpenHAB MQTT" 8 | 9 | boolean CPlugin_005(byte function, struct EventStruct *event) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_005; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_005)); 19 | Protocol[protocolCount].usesMQTT = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_TEMPLATE: 27 | { 28 | strcpy_P(Settings.MQTTsubscribe, PSTR("/%sysname%/#")); 29 | strcpy_P(Settings.MQTTpublish, PSTR("/%sysname%/%tskname%/%valname%")); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_RECV: 34 | { 35 | // Split topic into array 36 | String tmpTopic = event->String1.substring(1); 37 | String topicSplit[10]; 38 | int SlashIndex = tmpTopic.indexOf('/'); 39 | byte count = 0; 40 | while (SlashIndex > 0 && count < 10 - 1) 41 | { 42 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 43 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 44 | SlashIndex = tmpTopic.indexOf('/'); 45 | count++; 46 | } 47 | topicSplit[count] = tmpTopic; 48 | 49 | String cmd = topicSplit[1]; 50 | struct EventStruct TempEvent; 51 | TempEvent.Par1 = topicSplit[2].toInt(); 52 | TempEvent.Par2 = event->String2.toFloat(); 53 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 54 | break; 55 | } 56 | 57 | case CPLUGIN_PROTOCOL_SEND: 58 | { 59 | // MQTT publish structure: 60 | // /// 61 | 62 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 63 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 64 | 65 | String pubname = Settings.MQTTpublish; 66 | pubname.replace("%sysname%", Settings.Name); 67 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 68 | pubname.replace("%id%", String(event->idx)); 69 | 70 | String value = ""; 71 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 72 | 73 | switch (event->sensorType) 74 | { 75 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 76 | case SENSOR_TYPE_SWITCH: 77 | case SENSOR_TYPE_DIMMER: 78 | pubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 79 | value = String(UserVar[event->BaseVarIndex]); 80 | MQTTclient.publish(pubname, value); 81 | break; 82 | case SENSOR_TYPE_LONG: 83 | pubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 84 | value += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 85 | MQTTclient.publish(pubname, value); 86 | break; 87 | case SENSOR_TYPE_TEMP_HUM: 88 | case SENSOR_TYPE_TEMP_BARO: 89 | { 90 | String tmppubname = pubname; 91 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 92 | value = String(UserVar[event->BaseVarIndex]); 93 | MQTTclient.publish(tmppubname, value); 94 | tmppubname = pubname; 95 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[1]); 96 | value = String(UserVar[event->BaseVarIndex + 1]); 97 | MQTTclient.publish(tmppubname, value); 98 | break; 99 | } 100 | case SENSOR_TYPE_TEMP_HUM_BARO: 101 | { 102 | String tmppubname = pubname; 103 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 104 | value = String(UserVar[event->BaseVarIndex]); 105 | MQTTclient.publish(tmppubname, value); 106 | tmppubname = pubname; 107 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[1]); 108 | value = String(UserVar[event->BaseVarIndex + 1]); 109 | MQTTclient.publish(tmppubname, value); 110 | tmppubname = pubname; 111 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[2]); 112 | value = String(UserVar[event->BaseVarIndex + 2]); 113 | MQTTclient.publish(tmppubname, value); 114 | break; 115 | } 116 | } 117 | 118 | } 119 | return success; 120 | } 121 | } 122 | 123 | -------------------------------------------------------------------------------- /_C006.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) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_006; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_006)); 19 | Protocol[protocolCount].usesMQTT = true; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_TEMPLATE: 27 | { 28 | strcpy_P(Settings.MQTTsubscribe, PSTR("/Home/#")); 29 | strcpy_P(Settings.MQTTpublish, PSTR("/hooks/devices/%id%/SensorData/%valname%")); 30 | break; 31 | } 32 | 33 | case CPLUGIN_PROTOCOL_RECV: 34 | { 35 | // topic structure /Home/Floor/Location/device//gpio/16 36 | // Split topic into array 37 | String tmpTopic = event->String1.substring(1); 38 | String topicSplit[10]; 39 | int SlashIndex = tmpTopic.indexOf('/'); 40 | byte count = 0; 41 | while (SlashIndex > 0 && count < 10 - 1) 42 | { 43 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 44 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 45 | SlashIndex = tmpTopic.indexOf('/'); 46 | count++; 47 | } 48 | topicSplit[count] = tmpTopic; 49 | 50 | String name = topicSplit[4]; 51 | String cmd = topicSplit[5]; 52 | struct EventStruct TempEvent; 53 | TempEvent.Par1 = topicSplit[6].toInt(); 54 | TempEvent.Par2 = 0; 55 | if (event->String2 == "false" || event->String2 == "true") 56 | { 57 | if (event->String2 == "true") 58 | TempEvent.Par2 = 1; 59 | } 60 | else 61 | TempEvent.Par2 = event->String2.toFloat(); 62 | if (name == Settings.Name) 63 | { 64 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 65 | } 66 | break; 67 | } 68 | 69 | case CPLUGIN_PROTOCOL_SEND: 70 | { 71 | // MQTT publish structure: 72 | // /hooks/devices/idx/groupid/value name 73 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 74 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 75 | 76 | String pubname = Settings.MQTTpublish; 77 | pubname.replace("%sysname%", Settings.Name); 78 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 79 | pubname.replace("%id%", String(event->idx)); 80 | 81 | String value = ""; 82 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 83 | 84 | switch (event->sensorType) 85 | { 86 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 87 | case SENSOR_TYPE_SWITCH: 88 | case SENSOR_TYPE_DIMMER: 89 | pubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 90 | value = String(UserVar[event->BaseVarIndex]); 91 | MQTTclient.publish(pubname, value); 92 | break; 93 | case SENSOR_TYPE_LONG: 94 | pubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 95 | value += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 96 | MQTTclient.publish(pubname, value); 97 | break; 98 | case SENSOR_TYPE_TEMP_HUM: 99 | case SENSOR_TYPE_TEMP_BARO: 100 | { 101 | String tmppubname = pubname; 102 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 103 | value = String(UserVar[event->BaseVarIndex]); 104 | MQTTclient.publish(tmppubname, value); 105 | tmppubname = pubname; 106 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[1]); 107 | value = String(UserVar[event->BaseVarIndex + 1]); 108 | MQTTclient.publish(tmppubname, value); 109 | break; 110 | } 111 | case SENSOR_TYPE_TEMP_HUM_BARO: 112 | { 113 | String tmppubname = pubname; 114 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[0]); 115 | value = String(UserVar[event->BaseVarIndex]); 116 | MQTTclient.publish(tmppubname, value); 117 | tmppubname = pubname; 118 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[1]); 119 | value = String(UserVar[event->BaseVarIndex + 1]); 120 | MQTTclient.publish(tmppubname, value); 121 | tmppubname = pubname; 122 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[2]); 123 | value = String(UserVar[event->BaseVarIndex + 2]); 124 | MQTTclient.publish(tmppubname, value); 125 | break; 126 | } 127 | } 128 | 129 | } 130 | return success; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /_C007.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) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_007; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_007)); 19 | Protocol[protocolCount].usesMQTT = false; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 80; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_SEND: 27 | { 28 | char log[80]; 29 | boolean success = false; 30 | char host[20]; 31 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 32 | 33 | sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host); 34 | addLog(LOG_LEVEL_DEBUG, log); 35 | if (printToWeb) 36 | { 37 | printWebString += log; 38 | printWebString += "
"; 39 | } 40 | // Use WiFiClient class to create TCP connections 41 | WiFiClient client; 42 | if (!client.connect(host, Settings.ControllerPort)) 43 | { 44 | connectionFailures++; 45 | strcpy_P(log, PSTR("HTTP : connection failed")); 46 | addLog(LOG_LEVEL_ERROR, log); 47 | if (printToWeb) 48 | printWebString += F("connection failed
"); 49 | return false; 50 | } 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | String postDataStr = F("GET /emoncms/input/post.json?node="); 55 | 56 | postDataStr += Settings.Unit; 57 | postDataStr += F("&json="); 58 | 59 | switch (event->sensorType) 60 | { 61 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 62 | postDataStr += F("{field"); 63 | postDataStr += event->idx; 64 | postDataStr += ":"; 65 | postDataStr += String(UserVar[event->BaseVarIndex]); 66 | postDataStr += "}"; 67 | break; 68 | case SENSOR_TYPE_TEMP_HUM: // dual value 69 | case SENSOR_TYPE_TEMP_BARO: 70 | postDataStr += F("{field"); 71 | postDataStr += event->idx; 72 | postDataStr += ":"; 73 | postDataStr += String(UserVar[event->BaseVarIndex]); 74 | postDataStr += F(",field"); 75 | postDataStr += event->idx + 1; 76 | postDataStr += ":"; 77 | postDataStr += String(UserVar[event->BaseVarIndex + 1]); 78 | postDataStr += "}"; 79 | break; 80 | case SENSOR_TYPE_TEMP_HUM_BARO: 81 | postDataStr += F("{field"); 82 | postDataStr += event->idx; 83 | postDataStr += ":"; 84 | postDataStr += String(UserVar[event->BaseVarIndex]); 85 | postDataStr += F(",field"); 86 | postDataStr += event->idx + 1; 87 | postDataStr += ":"; 88 | postDataStr += String(UserVar[event->BaseVarIndex + 1]); 89 | postDataStr += F(",field"); 90 | postDataStr += event->idx + 2; 91 | postDataStr += ":"; 92 | postDataStr += String(UserVar[event->BaseVarIndex + 2]); 93 | postDataStr += "}"; 94 | break; 95 | case SENSOR_TYPE_SWITCH: 96 | break; 97 | } 98 | postDataStr += F("&apikey="); 99 | postDataStr += SecuritySettings.ControllerPassword; // "0UDNN17RW6XAS2E5" // api key 100 | 101 | postDataStr += F("\r\n\r\n"); 102 | 103 | String postStr = F("POST /update HTTP/1.1\n"); 104 | postStr += F("Host: emoncms.org\n"); 105 | postStr += F("Connection: close\n"); 106 | postStr += F("X-EMONCMSAPIKEY: "); 107 | postStr += SecuritySettings.ControllerPassword; 108 | postStr += "\n"; 109 | postStr += F("Content-Type: application/x-www-form-urlencoded\n"); 110 | postStr += F("Content-Length: "); 111 | postStr += postDataStr.length(); 112 | postStr += F("\n\n"); 113 | postDataStr += postStr; 114 | 115 | //postStr += postDataStr; 116 | 117 | if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) 118 | Serial.println(postDataStr); 119 | 120 | // This will send the request to the server 121 | client.print(postDataStr); 122 | 123 | unsigned long timer = millis() + 200; 124 | while (!client.available() && millis() < timer) 125 | delay(1); 126 | 127 | // Read all the lines of the reply from server and print them to Serial 128 | while (client.available()) { 129 | String line = client.readStringUntil('\n'); 130 | line.toCharArray(log, 80); 131 | addLog(LOG_LEVEL_DEBUG_MORE, log); 132 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 133 | { 134 | strcpy_P(log, PSTR("HTTP : Succes!")); 135 | addLog(LOG_LEVEL_DEBUG, log); 136 | if (printToWeb) 137 | printWebString += F("Success
"); 138 | success = true; 139 | } 140 | delay(1); 141 | } 142 | strcpy_P(log, PSTR("HTTP : closing connection")); 143 | addLog(LOG_LEVEL_DEBUG, log); 144 | if (printToWeb) 145 | printWebString += F("closing connection
"); 146 | 147 | client.flush(); 148 | client.stop(); 149 | break; 150 | } 151 | 152 | } 153 | return success; 154 | } 155 | 156 | -------------------------------------------------------------------------------- /_C008.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) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_008; 18 | strcpy_P(Protocol[protocolCount].Name, PSTR(CPLUGIN_NAME_008)); 19 | Protocol[protocolCount].usesMQTT = false; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 80; 23 | break; 24 | } 25 | 26 | case CPLUGIN_PROTOCOL_SEND: 27 | { 28 | switch (event->sensorType) 29 | { 30 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 31 | case SENSOR_TYPE_SWITCH: 32 | case SENSOR_TYPE_DIMMER: 33 | HTTPSend(event, 0, UserVar[event->BaseVarIndex], 0); 34 | break; 35 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 36 | HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 37 | break; 38 | case SENSOR_TYPE_TEMP_HUM: 39 | case SENSOR_TYPE_TEMP_BARO: 40 | { 41 | HTTPSend(event, 0, UserVar[event->BaseVarIndex], 0); 42 | unsigned long timer = millis() + Settings.MessageDelay; 43 | while (millis() < timer) 44 | backgroundtasks(); 45 | HTTPSend(event, 1, UserVar[event->BaseVarIndex + 1], 0); 46 | break; 47 | } 48 | case SENSOR_TYPE_TEMP_HUM_BARO: 49 | { 50 | HTTPSend(event, 0, UserVar[event->BaseVarIndex], 0); 51 | unsigned long timer = millis() + Settings.MessageDelay; 52 | while (millis() < timer) 53 | backgroundtasks(); 54 | HTTPSend(event, 1, UserVar[event->BaseVarIndex + 1], 0); 55 | timer = millis() + Settings.MessageDelay; 56 | while (millis() < timer) 57 | backgroundtasks(); 58 | HTTPSend(event, 2, UserVar[event->BaseVarIndex + 2], 0); 59 | break; 60 | } 61 | } 62 | break; 63 | } 64 | 65 | } 66 | return success; 67 | } 68 | 69 | 70 | //******************************************************************************** 71 | // Generic HTTP get request 72 | //******************************************************************************** 73 | boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 74 | { 75 | char log[80]; 76 | boolean success = false; 77 | char host[20]; 78 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 79 | 80 | sprintf_P(log, PSTR("%s%s"), "HTTP : connecting to ", host); 81 | addLog(LOG_LEVEL_DEBUG, log); 82 | if (printToWeb) 83 | { 84 | printWebString += log; 85 | printWebString += "
"; 86 | } 87 | // Use WiFiClient class to create TCP connections 88 | WiFiClient client; 89 | if (!client.connect(host, Settings.ControllerPort)) 90 | { 91 | connectionFailures++; 92 | strcpy_P(log, PSTR("HTTP : connection failed")); 93 | addLog(LOG_LEVEL_ERROR, log); 94 | if (printToWeb) 95 | printWebString += F("connection failed
"); 96 | return false; 97 | } 98 | if (connectionFailures) 99 | connectionFailures--; 100 | 101 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 102 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 103 | 104 | String url = "/"; 105 | url += Settings.MQTTpublish; 106 | url.replace("%sysname%", URLEncode(Settings.Name)); 107 | url.replace("%tskname%", URLEncode(ExtraTaskSettings.TaskDeviceName)); 108 | url.replace("%id%", String(event->idx)); 109 | url.replace("%valname%", URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex])); 110 | if (longValue) 111 | url.replace("%value%", String(longValue)); 112 | else 113 | url.replace("%value%", String(value)); 114 | 115 | url.toCharArray(log, 80); 116 | addLog(LOG_LEVEL_DEBUG_MORE, log); 117 | if (printToWeb) 118 | { 119 | printWebString += log; 120 | printWebString += "
"; 121 | } 122 | 123 | // This will send the request to the server 124 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 125 | "Host: " + host + "\r\n" + 126 | "Connection: close\r\n\r\n"); 127 | 128 | unsigned long timer = millis() + 200; 129 | while (!client.available() && millis() < timer) 130 | delay(1); 131 | 132 | // Read all the lines of the reply from server and print them to Serial 133 | while (client.available()) { 134 | String line = client.readStringUntil('\n'); 135 | line.toCharArray(log, 80); 136 | addLog(LOG_LEVEL_DEBUG_MORE, log); 137 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 138 | { 139 | strcpy_P(log, PSTR("HTTP : Succes!")); 140 | addLog(LOG_LEVEL_DEBUG, log); 141 | if (printToWeb) 142 | printWebString += F("Success
"); 143 | success = true; 144 | } 145 | delay(1); 146 | } 147 | strcpy_P(log, PSTR("HTTP : closing connection")); 148 | addLog(LOG_LEVEL_DEBUG, log); 149 | if (printToWeb) 150 | printWebString += F("closing connection
"); 151 | 152 | client.flush(); 153 | client.stop(); 154 | } 155 | 156 | -------------------------------------------------------------------------------- /_P001_Switch.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 001: Input Switch ######################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_001 6 | #define PLUGIN_ID_001 1 7 | #define PLUGIN_NAME_001 "Switch input" 8 | #define PLUGIN_VALUENAME1_001 "Switch" 9 | 10 | boolean Plugin_001(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte switchstate[TASKS_MAX]; 14 | static byte outputstate[TASKS_MAX]; 15 | 16 | switch (function) 17 | { 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_001; 21 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 22 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 23 | Device[deviceCount].Ports = 0; 24 | Device[deviceCount].PullUpOption = true; 25 | Device[deviceCount].InverseLogicOption = true; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_001); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_001)); 41 | break; 42 | } 43 | 44 | case PLUGIN_WEBFORM_LOAD: 45 | { 46 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 47 | String options[2]; 48 | options[0] = F("Switch"); 49 | options[1] = F("Dimmer"); 50 | int optionValues[2]; 51 | optionValues[0] = 1; 52 | optionValues[1] = 2; 53 | string += F("Switch Type:"); 66 | 67 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 68 | { 69 | char tmpString[128]; 70 | sprintf_P(tmpString, PSTR("Dim value:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 71 | string += tmpString; 72 | } 73 | 74 | choice = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 75 | String buttonOptions[3]; 76 | buttonOptions[0] = F("Normal Switch"); 77 | buttonOptions[1] = F("Push Button Active Low"); 78 | buttonOptions[2] = F("Push Button Active High"); 79 | int buttonOptionValues[3]; 80 | buttonOptionValues[0] = 0; 81 | buttonOptionValues[1] = 1; 82 | buttonOptionValues[2] = 2; 83 | string += F("Switch Button Type:"); 96 | 97 | success = true; 98 | break; 99 | } 100 | 101 | case PLUGIN_WEBFORM_SAVE: 102 | { 103 | String plugin1 = WebServer.arg("plugin_001_type"); 104 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 105 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 106 | { 107 | String plugin2 = WebServer.arg("plugin_001_dimvalue"); 108 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 109 | } 110 | String plugin3 = WebServer.arg("plugin_001_button"); 111 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); 112 | 113 | success = true; 114 | break; 115 | } 116 | 117 | case PLUGIN_INIT: 118 | { 119 | if (Settings.TaskDevicePin1PullUp[event->TaskIndex]) 120 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 121 | else 122 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT); 123 | switchstate[event->TaskIndex] = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]); 124 | success = true; 125 | break; 126 | } 127 | 128 | case PLUGIN_TEN_PER_SECOND: 129 | { 130 | byte state = digitalRead(Settings.TaskDevicePin1[event->TaskIndex]); 131 | if (state != switchstate[event->TaskIndex]) 132 | { 133 | switchstate[event->TaskIndex] = state; 134 | byte currentOutputState = outputstate[event->TaskIndex]; 135 | 136 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 0) //normal switch 137 | outputstate[event->TaskIndex] = state; 138 | else 139 | { 140 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] == 1) // active low push button 141 | { 142 | if (state == 0) 143 | outputstate[event->TaskIndex] = !outputstate[event->TaskIndex]; 144 | } 145 | else // active high push button 146 | { 147 | if (state == 1) 148 | outputstate[event->TaskIndex] = !outputstate[event->TaskIndex]; 149 | } 150 | } 151 | 152 | // send if output needs to be changed 153 | if (currentOutputState != outputstate[event->TaskIndex]) 154 | { 155 | byte sendState = outputstate[event->TaskIndex]; 156 | if (Settings.TaskDevicePin1Inversed[event->TaskIndex]) 157 | sendState = !outputstate[event->TaskIndex]; 158 | UserVar[event->BaseVarIndex] = sendState; 159 | event->sensorType = SENSOR_TYPE_SWITCH; 160 | if ((sendState == 1) && (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2)) 161 | { 162 | event->sensorType = SENSOR_TYPE_DIMMER; 163 | UserVar[event->BaseVarIndex] = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 164 | } 165 | String log = F("SW : State "); 166 | log += sendState; 167 | addLog(LOG_LEVEL_INFO, log); 168 | sendData(event); 169 | } 170 | } 171 | success = true; 172 | break; 173 | } 174 | 175 | case PLUGIN_WRITE: 176 | { 177 | String tmpString = string; 178 | int argIndex = tmpString.indexOf(','); 179 | if (argIndex) 180 | tmpString = tmpString.substring(0, argIndex); 181 | if (tmpString.equalsIgnoreCase("GPIO")) 182 | { 183 | success = true; 184 | if (event->Par1 >= 0 && event->Par1 <= 16) 185 | { 186 | pinMode(event->Par1, OUTPUT); 187 | digitalWrite(event->Par1, event->Par2); 188 | if (printToWeb) 189 | { 190 | printWebString += F("GPIO "); 191 | printWebString += event->Par1; 192 | printWebString += F(" Set to "); 193 | printWebString += event->Par2; 194 | printWebString += F("
"); 195 | } 196 | } 197 | } 198 | 199 | if (tmpString.equalsIgnoreCase("PWM")) 200 | { 201 | success = true; 202 | if (event->Par1 >= 0 && event->Par1 <= 1023) 203 | { 204 | pinMode(event->Par1, OUTPUT); 205 | analogWrite(event->Par1, event->Par2); 206 | if (printToWeb) 207 | { 208 | printWebString += F("GPIO "); 209 | printWebString += event->Par1; 210 | printWebString += F(" Set PWM to "); 211 | printWebString += event->Par2; 212 | printWebString += F("
"); 213 | } 214 | } 215 | } 216 | 217 | if (tmpString.equalsIgnoreCase("Pulse")) 218 | { 219 | success = true; 220 | if (event->Par1 >= 0 && event->Par1 <= 1023) 221 | { 222 | pinMode(event->Par1, OUTPUT); 223 | digitalWrite(event->Par1, event->Par2); 224 | delay(event->Par3); 225 | digitalWrite(event->Par1, !event->Par2); 226 | if (printToWeb) 227 | { 228 | printWebString += F("GPIO "); 229 | printWebString += event->Par1; 230 | printWebString += F(" Pulsed for "); 231 | printWebString += event->Par3; 232 | printWebString += F(" mS
"); 233 | } 234 | } 235 | } 236 | 237 | if (tmpString.equalsIgnoreCase("Servo")) 238 | { 239 | success = true; 240 | if (event->Par1 >= 0 && event->Par1 <= 2) 241 | switch (event->Par1) 242 | { 243 | case 1: 244 | myservo1.attach(event->Par2); 245 | myservo1.write(event->Par3); 246 | break; 247 | case 2: 248 | myservo2.attach(event->Par2); 249 | myservo2.write(event->Par3); 250 | break; 251 | } 252 | { 253 | if (printToWeb) 254 | { 255 | printWebString += F("GPIO "); 256 | printWebString += event->Par2; 257 | printWebString += F(" Servo set to "); 258 | printWebString += event->Par3; 259 | printWebString += F("
"); 260 | } 261 | } 262 | } 263 | 264 | break; 265 | } 266 | } 267 | return success; 268 | } 269 | -------------------------------------------------------------------------------- /_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].GlobalSyncOption = true; 28 | break; 29 | } 30 | 31 | case PLUGIN_GET_DEVICENAME: 32 | { 33 | string = F(PLUGIN_NAME_002); 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICEVALUENAMES: 38 | { 39 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002)); 40 | break; 41 | } 42 | 43 | case PLUGIN_READ: 44 | { 45 | int value = analogRead(A0); 46 | UserVar[event->BaseVarIndex] = (float)value; 47 | String log = F("ADC : Analog value: "); 48 | log += value; 49 | addLog(LOG_LEVEL_INFO,log); 50 | success = true; 51 | break; 52 | } 53 | } 54 | return success; 55 | } 56 | -------------------------------------------------------------------------------- /_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 | 11 | unsigned long Plugin_003_pulseCounter[TASKS_MAX]; 12 | unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX]; 13 | unsigned long Plugin_003_pulseTime[TASKS_MAX]; 14 | unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX]; 15 | 16 | boolean Plugin_003(byte function, struct EventStruct *event, String& string) 17 | { 18 | boolean success = false; 19 | 20 | switch (function) 21 | { 22 | 23 | case PLUGIN_DEVICE_ADD: 24 | { 25 | Device[++deviceCount].Number = PLUGIN_ID_003; 26 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 27 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 28 | Device[deviceCount].Ports = 0; 29 | Device[deviceCount].PullUpOption = false; 30 | Device[deviceCount].InverseLogicOption = false; 31 | Device[deviceCount].FormulaOption = true; 32 | Device[deviceCount].ValueCount = 2; 33 | Device[deviceCount].SendDataOption = true; 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICENAME: 38 | { 39 | string = F(PLUGIN_NAME_003); 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICEVALUENAMES: 44 | { 45 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003)); 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003)); 47 | break; 48 | } 49 | 50 | case PLUGIN_WEBFORM_LOAD: 51 | { 52 | char tmpString[128]; 53 | sprintf_P(tmpString, PSTR("Debounce Time (mSec):"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 54 | string += tmpString; 55 | success = true; 56 | break; 57 | } 58 | 59 | case PLUGIN_WEBFORM_SAVE: 60 | { 61 | String plugin1 = WebServer.arg("plugin_003"); 62 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 63 | success = true; 64 | break; 65 | } 66 | 67 | case PLUGIN_WEBFORM_SHOW_VALUES: 68 | { 69 | string += ExtraTaskSettings.TaskDeviceValueNames[0]; 70 | string += F(":"); 71 | string += Plugin_003_pulseCounter[event->TaskIndex]; 72 | string += F("
"); 73 | string += ExtraTaskSettings.TaskDeviceValueNames[1]; 74 | string += F(":"); 75 | string += Plugin_003_pulseTotalCounter[event->TaskIndex]; 76 | string += F("
Time:"); 77 | string += Plugin_003_pulseTime[event->TaskIndex]; 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_INIT: 83 | { 84 | String log = F("INIT : Pulse "); 85 | log += Settings.TaskDevicePin1[event->TaskIndex]; 86 | addLog(LOG_LEVEL_INFO,log); 87 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 88 | Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex); 89 | success = true; 90 | break; 91 | } 92 | 93 | case PLUGIN_READ: 94 | { 95 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 96 | Plugin_003_pulseCounter[event->TaskIndex] = 0; 97 | success = true; 98 | break; 99 | } 100 | } 101 | return success; 102 | } 103 | 104 | 105 | /*********************************************************************************************\ 106 | * Check Pulse Counters (called from irq handler) 107 | \*********************************************************************************************/ 108 | void Plugin_003_pulsecheck(byte Index) 109 | { 110 | unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index]; 111 | if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task 112 | { 113 | Plugin_003_pulseCounter[Index]++; 114 | Plugin_003_pulseTotalCounter[Index]++; 115 | Plugin_003_pulseTime[Index] = PulseTime; 116 | Plugin_003_pulseTimePrevious[Index]=millis(); 117 | } 118 | } 119 | 120 | 121 | /*********************************************************************************************\ 122 | * Pulse Counter IRQ handlers 123 | \*********************************************************************************************/ 124 | void Plugin_003_pulse_interrupt1() 125 | { 126 | Plugin_003_pulsecheck(0); 127 | } 128 | void Plugin_003_pulse_interrupt2() 129 | { 130 | Plugin_003_pulsecheck(1); 131 | } 132 | void Plugin_003_pulse_interrupt3() 133 | { 134 | Plugin_003_pulsecheck(2); 135 | } 136 | void Plugin_003_pulse_interrupt4() 137 | { 138 | Plugin_003_pulsecheck(3); 139 | } 140 | void Plugin_003_pulse_interrupt5() 141 | { 142 | Plugin_003_pulsecheck(4); 143 | } 144 | void Plugin_003_pulse_interrupt6() 145 | { 146 | Plugin_003_pulsecheck(5); 147 | } 148 | void Plugin_003_pulse_interrupt7() 149 | { 150 | Plugin_003_pulsecheck(6); 151 | } 152 | void Plugin_003_pulse_interrupt8() 153 | { 154 | Plugin_003_pulsecheck(7); 155 | } 156 | 157 | 158 | /*********************************************************************************************\ 159 | * Init Pulse Counters 160 | \*********************************************************************************************/ 161 | void Plugin_003_pulseinit(byte Par1, byte Index) 162 | { 163 | // Init IO pins 164 | String log = F("PULSE: Init"); 165 | addLog(LOG_LEVEL_INFO,log); 166 | 167 | switch (Index) 168 | { 169 | case 0: 170 | attachInterrupt(Par1, Plugin_003_pulse_interrupt1, FALLING); 171 | break; 172 | case 1: 173 | attachInterrupt(Par1, Plugin_003_pulse_interrupt2, FALLING); 174 | break; 175 | case 2: 176 | attachInterrupt(Par1, Plugin_003_pulse_interrupt3, FALLING); 177 | break; 178 | case 3: 179 | attachInterrupt(Par1, Plugin_003_pulse_interrupt4, FALLING); 180 | break; 181 | case 4: 182 | attachInterrupt(Par1, Plugin_003_pulse_interrupt5, FALLING); 183 | break; 184 | case 5: 185 | attachInterrupt(Par1, Plugin_003_pulse_interrupt6, FALLING); 186 | break; 187 | case 6: 188 | attachInterrupt(Par1, Plugin_003_pulse_interrupt7, FALLING); 189 | break; 190 | case 7: 191 | attachInterrupt(Par1, Plugin_003_pulse_interrupt8, FALLING); 192 | break; 193 | } 194 | } 195 | 196 | -------------------------------------------------------------------------------- /_P005_DHT.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 006: 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 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_005); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_005)); 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_005)); 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("DHT 11"); 51 | options[1] = F("DHT 22"); 52 | int optionValues[2]; 53 | optionValues[0] = 11; 54 | optionValues[1] = 22; 55 | string += F("DHT Type:"); 68 | 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_WEBFORM_SAVE: 74 | { 75 | String plugin1 = WebServer.arg("plugin_005_dhttype"); 76 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 77 | success = true; 78 | break; 79 | } 80 | 81 | case PLUGIN_READ: 82 | { 83 | byte dht_dat[5]; 84 | byte dht_in; 85 | byte i; 86 | byte Retry = 0; 87 | boolean error = false; 88 | 89 | byte Par3 = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 90 | Plugin_005_DHT_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 91 | 92 | pinMode(Plugin_005_DHT_Pin, OUTPUT); 93 | // DHT start condition, pull-down i/o pin for 18ms 94 | digitalWrite(Plugin_005_DHT_Pin, LOW); // Pull low 95 | delay(18); 96 | digitalWrite(Plugin_005_DHT_Pin, HIGH); // Pull high 97 | delayMicroseconds(40); 98 | pinMode(Plugin_005_DHT_Pin, INPUT); // change pin to input 99 | delayMicroseconds(10); 100 | 101 | dht_in = digitalRead(Plugin_005_DHT_Pin); 102 | if (!dht_in) 103 | { 104 | delayMicroseconds(80); 105 | dht_in = digitalRead(Plugin_005_DHT_Pin); 106 | if (dht_in) 107 | { 108 | delayMicroseconds(40); // now ready for data reception 109 | for (i = 0; i < 5; i++) 110 | { 111 | byte data = Plugin_005_read_dht_dat(); 112 | if (data != -1) 113 | dht_dat[i] = data; 114 | else 115 | { 116 | addLog(LOG_LEVEL_ERROR, (char*)"DHT : protocol timeout!"); 117 | error = true; 118 | } 119 | } 120 | 121 | if (!error) 122 | { 123 | 124 | // Checksum calculation is a Rollover Checksum by design! 125 | byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum 126 | 127 | if (dht_dat[4] == dht_check_sum) 128 | { 129 | float temperature = 0; 130 | float humidity = 0; 131 | 132 | if (Par3 == 11) 133 | { 134 | temperature = float(dht_dat[2]); // Temperature 135 | humidity = float(dht_dat[0]); // Humidity 136 | } 137 | 138 | if (Par3 == 22) 139 | { 140 | if (dht_dat[2] & 0x80) // negative temperature 141 | temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]); 142 | else 143 | temperature = 0.1 * word(dht_dat[2], dht_dat[3]); 144 | humidity = word(dht_dat[0], dht_dat[1]) * 0.1; // Humidity 145 | } 146 | if (temperature == 0 && humidity == 0) 147 | { 148 | String log = F("DHT : No reading!"); 149 | log += UserVar[event->BaseVarIndex]; 150 | addLog(LOG_LEVEL_INFO, log); 151 | } 152 | else 153 | { 154 | UserVar[event->BaseVarIndex] = temperature; 155 | UserVar[event->BaseVarIndex + 1] = humidity; 156 | String log = F("DHT : Temperature: "); 157 | log += UserVar[event->BaseVarIndex]; 158 | addLog(LOG_LEVEL_INFO, log); 159 | log = F("DHT : Humidity: "); 160 | log += UserVar[event->BaseVarIndex + 1]; 161 | addLog(LOG_LEVEL_INFO, log); 162 | success = true; 163 | } 164 | } // checksum 165 | } // error 166 | } // dht 167 | } // !dht 168 | if(!success) 169 | { 170 | UserVar[event->BaseVarIndex] = NAN; 171 | UserVar[event->BaseVarIndex + 1] = NAN; 172 | } 173 | break; 174 | } 175 | } 176 | return success; 177 | } 178 | 179 | 180 | /*********************************************************************************************\ 181 | * DHT sub to get an 8 bit value from the receiving bitstream 182 | \*********************************************************************************************/ 183 | int Plugin_005_read_dht_dat(void) 184 | { 185 | byte i = 0; 186 | byte result = 0; 187 | byte counter = 0; 188 | //noInterrupts(); 189 | for (i = 0; i < 8; i++) 190 | { 191 | while ((!digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 192 | { 193 | delayMicroseconds(1); 194 | counter++; 195 | } 196 | if (counter >= 100) 197 | { 198 | //interrupts(); 199 | return -1; 200 | } 201 | delayMicroseconds(30); 202 | if (digitalRead(Plugin_005_DHT_Pin)) 203 | result |= (1 << (7 - i)); 204 | counter = 0; 205 | while ((digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 206 | { 207 | delayMicroseconds(1); 208 | counter++; 209 | } 210 | if (counter >= 100) 211 | { 212 | //interrupts(); 213 | return -1; 214 | } 215 | } 216 | //interrupts(); 217 | return result; 218 | } 219 | 220 | -------------------------------------------------------------------------------- /_P006_BMP085.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 006 BMP0685 I2C Barometric Pressure Sensor ########################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_006 6 | #define PLUGIN_ID_006 6 7 | #define PLUGIN_NAME_006 "Temperature & Pressure - BMP085" 8 | #define PLUGIN_VALUENAME1_006 "Temperature" 9 | #define PLUGIN_VALUENAME2_006 "Pressure" 10 | 11 | boolean Plugin_006_init = false; 12 | 13 | boolean Plugin_006(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_006; 22 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 23 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_BARO; 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 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_006); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_006)); 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_006)); 43 | break; 44 | } 45 | 46 | case PLUGIN_READ: 47 | { 48 | if (!Plugin_006_init) 49 | { 50 | if (Plugin_006_bmp085_begin()) 51 | Plugin_006_init = true; 52 | } 53 | 54 | if (Plugin_006_init) 55 | { 56 | UserVar[event->BaseVarIndex] = Plugin_006_bmp085_readTemperature(); 57 | UserVar[event->BaseVarIndex + 1] = ((float)Plugin_006_bmp085_readPressure()) / 100; 58 | String log = F("BMP : Temperature: "); 59 | log += UserVar[event->BaseVarIndex]; 60 | addLog(LOG_LEVEL_INFO, log); 61 | log = F("BMP : Barometric Pressure: "); 62 | log += UserVar[event->BaseVarIndex + 1]; 63 | addLog(LOG_LEVEL_INFO, log); 64 | success = true; 65 | } 66 | break; 67 | } 68 | 69 | } 70 | return success; 71 | } 72 | 73 | #define BMP085_I2CADDR 0x77 74 | #define BMP085_ULTRAHIGHRES 3 75 | #define BMP085_CAL_AC1 0xAA // R Calibration data (16 bits) 76 | #define BMP085_CAL_AC2 0xAC // R Calibration data (16 bits) 77 | #define BMP085_CAL_AC3 0xAE // R Calibration data (16 bits) 78 | #define BMP085_CAL_AC4 0xB0 // R Calibration data (16 bits) 79 | #define BMP085_CAL_AC5 0xB2 // R Calibration data (16 bits) 80 | #define BMP085_CAL_AC6 0xB4 // R Calibration data (16 bits) 81 | #define BMP085_CAL_B1 0xB6 // R Calibration data (16 bits) 82 | #define BMP085_CAL_B2 0xB8 // R Calibration data (16 bits) 83 | #define BMP085_CAL_MB 0xBA // R Calibration data (16 bits) 84 | #define BMP085_CAL_MC 0xBC // R Calibration data (16 bits) 85 | #define BMP085_CAL_MD 0xBE // R Calibration data (16 bits) 86 | #define BMP085_CONTROL 0xF4 87 | #define BMP085_TEMPDATA 0xF6 88 | #define BMP085_PRESSUREDATA 0xF6 89 | #define BMP085_READTEMPCMD 0x2E 90 | #define BMP085_READPRESSURECMD 0x34 91 | 92 | uint8_t oversampling = BMP085_ULTRAHIGHRES; 93 | int16_t ac1, ac2, ac3, b1, b2, mb, mc, md; 94 | uint16_t ac4, ac5, ac6; 95 | 96 | /*********************************************************************/ 97 | boolean Plugin_006_bmp085_begin() 98 | /*********************************************************************/ 99 | { 100 | if (Plugin_006_bmp085_read8(0xD0) != 0x55) return false; 101 | 102 | /* read calibration data */ 103 | ac1 = Plugin_006_bmp085_read16(BMP085_CAL_AC1); 104 | ac2 = Plugin_006_bmp085_read16(BMP085_CAL_AC2); 105 | ac3 = Plugin_006_bmp085_read16(BMP085_CAL_AC3); 106 | ac4 = Plugin_006_bmp085_read16(BMP085_CAL_AC4); 107 | ac5 = Plugin_006_bmp085_read16(BMP085_CAL_AC5); 108 | ac6 = Plugin_006_bmp085_read16(BMP085_CAL_AC6); 109 | 110 | b1 = Plugin_006_bmp085_read16(BMP085_CAL_B1); 111 | b2 = Plugin_006_bmp085_read16(BMP085_CAL_B2); 112 | 113 | mb = Plugin_006_bmp085_read16(BMP085_CAL_MB); 114 | mc = Plugin_006_bmp085_read16(BMP085_CAL_MC); 115 | md = Plugin_006_bmp085_read16(BMP085_CAL_MD); 116 | } 117 | 118 | /*********************************************************************/ 119 | uint16_t Plugin_006_bmp085_readRawTemperature(void) 120 | /*********************************************************************/ 121 | { 122 | Plugin_006_bmp085_write8(BMP085_CONTROL, BMP085_READTEMPCMD); 123 | delay(5); 124 | return Plugin_006_bmp085_read16(BMP085_TEMPDATA); 125 | } 126 | 127 | /*********************************************************************/ 128 | uint32_t Plugin_006_bmp085_readRawPressure(void) 129 | /*********************************************************************/ 130 | { 131 | uint32_t raw; 132 | 133 | Plugin_006_bmp085_write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6)); 134 | 135 | delay(26); 136 | 137 | raw = Plugin_006_bmp085_read16(BMP085_PRESSUREDATA); 138 | raw <<= 8; 139 | raw |= Plugin_006_bmp085_read8(BMP085_PRESSUREDATA + 2); 140 | raw >>= (8 - oversampling); 141 | 142 | return raw; 143 | } 144 | 145 | /*********************************************************************/ 146 | int32_t Plugin_006_bmp085_readPressure(void) 147 | /*********************************************************************/ 148 | { 149 | int32_t UT, UP, B3, B5, B6, X1, X2, X3, p; 150 | uint32_t B4, B7; 151 | 152 | UT = Plugin_006_bmp085_readRawTemperature(); 153 | UP = Plugin_006_bmp085_readRawPressure(); 154 | 155 | // do temperature calculations 156 | X1 = (UT - (int32_t)(ac6)) * ((int32_t)(ac5)) / pow(2, 15); 157 | X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md); 158 | B5 = X1 + X2; 159 | 160 | // do pressure calcs 161 | B6 = B5 - 4000; 162 | X1 = ((int32_t)b2 * ( (B6 * B6) >> 12 )) >> 11; 163 | X2 = ((int32_t)ac2 * B6) >> 11; 164 | X3 = X1 + X2; 165 | B3 = ((((int32_t)ac1 * 4 + X3) << oversampling) + 2) / 4; 166 | 167 | X1 = ((int32_t)ac3 * B6) >> 13; 168 | X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16; 169 | X3 = ((X1 + X2) + 2) >> 2; 170 | B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15; 171 | B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling ); 172 | 173 | if (B7 < 0x80000000) 174 | { 175 | p = (B7 * 2) / B4; 176 | } 177 | else 178 | { 179 | p = (B7 / B4) * 2; 180 | } 181 | X1 = (p >> 8) * (p >> 8); 182 | X1 = (X1 * 3038) >> 16; 183 | X2 = (-7357 * p) >> 16; 184 | 185 | p = p + ((X1 + X2 + (int32_t)3791) >> 4); 186 | return p; 187 | } 188 | 189 | /*********************************************************************/ 190 | float Plugin_006_bmp085_readTemperature(void) 191 | /*********************************************************************/ 192 | { 193 | int32_t UT, X1, X2, B5; // following ds convention 194 | float temp; 195 | 196 | UT = Plugin_006_bmp085_readRawTemperature(); 197 | 198 | // step 1 199 | X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) / pow(2, 15); 200 | X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md); 201 | B5 = X1 + X2; 202 | temp = (B5 + 8) / pow(2, 4); 203 | temp /= 10; 204 | 205 | return temp; 206 | } 207 | 208 | /*********************************************************************/ 209 | uint8_t Plugin_006_bmp085_read8(uint8_t a) 210 | /*********************************************************************/ 211 | { 212 | uint8_t ret; 213 | 214 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 215 | Wire.write(a); // sends register address to read from 216 | Wire.endTransmission(); // end transmission 217 | 218 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 219 | Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read 220 | ret = Wire.read(); // receive DATA 221 | Wire.endTransmission(); // end transmission 222 | 223 | return ret; 224 | } 225 | 226 | /*********************************************************************/ 227 | uint16_t Plugin_006_bmp085_read16(uint8_t a) 228 | /*********************************************************************/ 229 | { 230 | uint16_t ret; 231 | 232 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 233 | Wire.write(a); // sends register address to read from 234 | Wire.endTransmission(); // end transmission 235 | 236 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 237 | Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read 238 | ret = Wire.read(); // receive DATA 239 | ret <<= 8; 240 | ret |= Wire.read(); // receive DATA 241 | Wire.endTransmission(); // end transmission 242 | 243 | return ret; 244 | } 245 | 246 | /*********************************************************************/ 247 | boolean Plugin_006_bmp085_write8(uint8_t a, uint8_t d) 248 | /*********************************************************************/ 249 | { 250 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 251 | Wire.write(a); // sends register address to read from 252 | Wire.write(d); // write data 253 | if(Wire.endTransmission() != 0) 254 | return false; 255 | 256 | return true; 257 | } 258 | -------------------------------------------------------------------------------- /_P007_PCF8591.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 007: ExtWiredAnalog ####################################### 3 | //####################################################################################################### 4 | 5 | /*********************************************************************************************\ 6 | * This plugin provides support for 4 extra analog inputs, using the PCF8591 (NXP/Philips) 7 | * Support : www.esp8266.nu 8 | * Date : Apr 2015 9 | * Compatibility : R004 10 | * Syntax : "ExtWiredAnalog , " 11 | ********************************************************************************************* 12 | * Technical description: 13 | * 14 | * De PCF8591 is a IO Expander chip that connects through the I2C bus 15 | * Basic I2C address = 0x48 16 | * Each chip has 4 analog inputs 17 | * This commando reads the analog input en stores the result into a variable 18 | \*********************************************************************************************/ 19 | #define PLUGIN_007 20 | #define PLUGIN_ID_007 7 21 | #define PLUGIN_NAME_007 "Analog input - PCF8591" 22 | #define PLUGIN_VALUENAME1_007 "Analog" 23 | 24 | boolean Plugin_007(byte function, struct EventStruct *event, String& string) 25 | { 26 | boolean success = false; 27 | 28 | static byte portValue = 0; 29 | 30 | switch (function) 31 | { 32 | case PLUGIN_DEVICE_ADD: 33 | { 34 | Device[++deviceCount].Number = PLUGIN_ID_007; 35 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 36 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 37 | Device[deviceCount].Ports = 4; 38 | Device[deviceCount].PullUpOption = false; 39 | Device[deviceCount].InverseLogicOption = false; 40 | Device[deviceCount].FormulaOption = true; 41 | Device[deviceCount].ValueCount = 1; 42 | Device[deviceCount].SendDataOption = true; 43 | break; 44 | } 45 | 46 | case PLUGIN_GET_DEVICENAME: 47 | { 48 | string = F(PLUGIN_NAME_007); 49 | break; 50 | } 51 | 52 | case PLUGIN_GET_DEVICEVALUENAMES: 53 | { 54 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_007)); 55 | break; 56 | } 57 | 58 | case PLUGIN_READ: 59 | { 60 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 61 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 62 | uint8_t address = 0x48 + unit; 63 | 64 | // get the current pin value 65 | Wire.beginTransmission(address); 66 | Wire.write(port - 1); 67 | Wire.endTransmission(); 68 | 69 | Wire.requestFrom(address, (uint8_t)0x2); 70 | if (Wire.available()) 71 | { 72 | Wire.read(); // Read older value first (stored in chip) 73 | UserVar[event->BaseVarIndex] = (float)Wire.read(); // now read actual value and store into Nodo var 74 | String log = F("PCF : Analog value: "); 75 | log += UserVar[event->BaseVarIndex]; 76 | addLog(LOG_LEVEL_INFO,log); 77 | success = true; 78 | } 79 | break; 80 | } 81 | } 82 | return success; 83 | } 84 | -------------------------------------------------------------------------------- /_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 | volatile byte Plugin_008_bitCount = 0; // Count the number of bits received. 13 | volatile unsigned long Plugin_008_keyBuffer = 0; // A 32-bit-long keyBuffer into which the number is stored. 14 | byte Plugin_008_bitCountPrev = 0; // to detect noise 15 | byte Plugin_008_Unit = 0; 16 | 17 | boolean Plugin_008_init = false; 18 | 19 | boolean Plugin_008(byte function, struct EventStruct *event, String& string) 20 | { 21 | boolean success = false; 22 | 23 | switch (function) 24 | { 25 | case PLUGIN_DEVICE_ADD: 26 | { 27 | Device[++deviceCount].Number = PLUGIN_ID_008; 28 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 29 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 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 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICENAME: 40 | { 41 | string = F(PLUGIN_NAME_008); 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICEVALUENAMES: 46 | { 47 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_008)); 48 | break; 49 | } 50 | 51 | case PLUGIN_WEBFORM_SHOW_VALUES: 52 | { 53 | string += F("
"); 54 | string += ExtraTaskSettings.TaskDeviceValueNames[0]; 55 | string += F(":
"); 56 | string += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 57 | string += F("
"); 58 | success = true; 59 | break; 60 | } 61 | 62 | case PLUGIN_INIT: 63 | { 64 | Plugin_008_init = true; 65 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 66 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 67 | attachInterrupt(Settings.TaskDevicePin1[event->TaskIndex], Plugin_008_interrupt1, FALLING); 68 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_008_interrupt2, FALLING); 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_ONCE_A_SECOND: 74 | { 75 | if (Plugin_008_init) 76 | { 77 | if ((Plugin_008_bitCount != PLUGIN_008_WGSIZE) && (Plugin_008_bitCount == Plugin_008_bitCountPrev)) 78 | { 79 | // must be noise 80 | Plugin_008_bitCount = 0; 81 | Plugin_008_keyBuffer = 0; 82 | } 83 | 84 | if (Plugin_008_bitCount == PLUGIN_008_WGSIZE) 85 | { 86 | Plugin_008_bitCount = 0; // Read in the current key and reset everything so that the interrupts can 87 | 88 | Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 1; // Strip leading and trailing parity bits from the keyBuffer 89 | Plugin_008_keyBuffer &= 0xFFFFFF; 90 | UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); 91 | UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); 92 | String log = F("RFID : Tag: "); 93 | log += Plugin_008_keyBuffer; 94 | addLog(LOG_LEVEL_INFO, log); 95 | event->sensorType = SENSOR_TYPE_LONG; 96 | sendData(event); 97 | } 98 | 99 | Plugin_008_bitCountPrev = Plugin_008_bitCount; // store this value for next check, detect noise 100 | } 101 | break; 102 | } 103 | } 104 | return success; 105 | } 106 | 107 | /*********************************************************************/ 108 | void Plugin_008_interrupt1() 109 | /*********************************************************************/ 110 | { 111 | // We've received a 1 bit. (bit 0 = high, bit 1 = low) 112 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 113 | Plugin_008_keyBuffer += 1; // Add the 1 (not necessary for the zeroes) 114 | Plugin_008_bitCount++; // Increment the bit count 115 | } 116 | 117 | /*********************************************************************/ 118 | void Plugin_008_interrupt2() 119 | /*********************************************************************/ 120 | { 121 | // We've received a 0 bit. (bit 0 = low, bit 1 = high) 122 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 123 | Plugin_008_bitCount++; // Increment the bit count 124 | } 125 | 126 | -------------------------------------------------------------------------------- /_P009_MCP.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 009: MCP23017 input ####################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_009 6 | #define PLUGIN_ID_009 9 7 | #define PLUGIN_NAME_009 "Switch input - MCP23017" 8 | #define PLUGIN_VALUENAME1_009 "Switch" 9 | 10 | boolean Plugin_009(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_009; 21 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 22 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 23 | Device[deviceCount].Ports = 16; 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 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_009); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_009)); 41 | break; 42 | } 43 | 44 | case PLUGIN_INIT: 45 | { 46 | // read and store current state to prevent switching at boot time 47 | switchstate[event->TaskIndex] = Plugin_009_Read(Settings.TaskDevicePort[event->TaskIndex]); 48 | // Turn on Pullup resistor 49 | Plugin_009_Config(Settings.TaskDevicePort[event->TaskIndex], 1); 50 | success = true; 51 | break; 52 | } 53 | 54 | case PLUGIN_TEN_PER_SECOND: 55 | { 56 | int state = Plugin_009_Read(Settings.TaskDevicePort[event->TaskIndex]); 57 | if (state != -1) 58 | { 59 | if (state != switchstate[event->TaskIndex]) 60 | { 61 | String log = F("MCP : State "); 62 | log += state; 63 | addLog(LOG_LEVEL_INFO,log); 64 | switchstate[event->TaskIndex] = state; 65 | UserVar[event->BaseVarIndex] = state; 66 | event->sensorType = SENSOR_TYPE_SWITCH; 67 | sendData(event); 68 | } 69 | } 70 | success = true; 71 | break; 72 | } 73 | 74 | case PLUGIN_WRITE: 75 | { 76 | String tmpString = string; 77 | int argIndex = tmpString.indexOf(','); 78 | if (argIndex) 79 | tmpString = tmpString.substring(0, argIndex); 80 | if (tmpString.equalsIgnoreCase("MCPGPIO")) 81 | { 82 | success = true; 83 | Plugin_009_Write(event->Par1, event->Par2); 84 | if (printToWeb) 85 | { 86 | printWebString += F("MCPGPIO "); 87 | printWebString += event->Par1; 88 | printWebString += F(" Set to "); 89 | printWebString += event->Par2; 90 | printWebString += F("
"); 91 | } 92 | } 93 | if (tmpString.equalsIgnoreCase("MCPGPIOPulse")) 94 | { 95 | success = true; 96 | if (event->Par1 >= 0 && event->Par1 <= 1023) 97 | { 98 | Plugin_009_Write(event->Par1, event->Par2); 99 | delay(event->Par3); 100 | Plugin_009_Write(event->Par1, !event->Par2); 101 | if (printToWeb) 102 | { 103 | printWebString += F("MCPGPIO "); 104 | printWebString += event->Par1; 105 | printWebString += F(" Pulsed for "); 106 | printWebString += event->Par3; 107 | printWebString += F(" mS
"); 108 | } 109 | } 110 | } 111 | break; 112 | } 113 | } 114 | return success; 115 | } 116 | 117 | 118 | //******************************************************************************** 119 | // MCP23017 read 120 | //******************************************************************************** 121 | int Plugin_009_Read(byte Par1) 122 | { 123 | int8_t state = -1; 124 | byte unit = (Par1 - 1) / 16; 125 | byte port = Par1 - (unit * 16); 126 | uint8_t address = 0x20 + unit; 127 | byte IOBankValueReg = 0x12; 128 | if (port > 8) 129 | { 130 | port = port - 8; 131 | IOBankValueReg++; 132 | } 133 | // get the current pin status 134 | Wire.beginTransmission(address); 135 | Wire.write(IOBankValueReg); // IO data register 136 | Wire.endTransmission(); 137 | Wire.requestFrom(address, (uint8_t)0x1); 138 | if (Wire.available()) 139 | { 140 | state = ((Wire.read() & _BV(port - 1)) >> (port - 1)); 141 | } 142 | return state; 143 | } 144 | 145 | 146 | //******************************************************************************** 147 | // MCP23017 write 148 | //******************************************************************************** 149 | boolean Plugin_009_Write(byte Par1, byte Par2) 150 | { 151 | boolean success = false; 152 | byte portvalue = 0; 153 | byte unit = (Par1 - 1) / 16; 154 | byte port = Par1 - (unit * 16); 155 | uint8_t address = 0x20 + unit; 156 | byte IOBankConfigReg = 0; 157 | byte IOBankValueReg = 0x12; 158 | if (port > 8) 159 | { 160 | port = port - 8; 161 | IOBankConfigReg++; 162 | IOBankValueReg++; 163 | } 164 | // turn this port into output, first read current config 165 | Wire.beginTransmission(address); 166 | Wire.write(IOBankConfigReg); // IO config register 167 | Wire.endTransmission(); 168 | Wire.requestFrom(address, (uint8_t)0x1); 169 | if (Wire.available()) 170 | { 171 | portvalue = Wire.read(); 172 | portvalue &= ~(1 << (port - 1)); // change pin from (default) input to output 173 | 174 | // write new IO config 175 | Wire.beginTransmission(address); 176 | Wire.write(IOBankConfigReg); // IO config register 177 | Wire.write(portvalue); 178 | Wire.endTransmission(); 179 | } 180 | // get the current pin status 181 | Wire.beginTransmission(address); 182 | Wire.write(IOBankValueReg); // IO data register 183 | Wire.endTransmission(); 184 | Wire.requestFrom(address, (uint8_t)0x1); 185 | if (Wire.available()) 186 | { 187 | portvalue = Wire.read(); 188 | if (Par2 == 1) 189 | portvalue |= (1 << (port - 1)); 190 | else 191 | portvalue &= ~(1 << (port - 1)); 192 | 193 | // write back new data 194 | Wire.beginTransmission(address); 195 | Wire.write(IOBankValueReg); 196 | Wire.write(portvalue); 197 | Wire.endTransmission(); 198 | success = true; 199 | } 200 | } 201 | 202 | 203 | //******************************************************************************** 204 | // MCP23017 config 205 | //******************************************************************************** 206 | boolean Plugin_009_Config(byte Par1, byte Par2) 207 | { 208 | boolean success = false; 209 | byte portvalue = 0; 210 | byte unit = (Par1 - 1) / 16; 211 | byte port = Par1 - (unit * 16); 212 | uint8_t address = 0x20 + unit; 213 | byte IOBankConfigReg = 0xC; 214 | if (port > 8) 215 | { 216 | port = port - 8; 217 | IOBankConfigReg++; 218 | } 219 | // turn this port pullup on 220 | Wire.beginTransmission(address); 221 | Wire.write(IOBankConfigReg); 222 | Wire.endTransmission(); 223 | Wire.requestFrom(address, (uint8_t)0x1); 224 | if (Wire.available()) 225 | { 226 | portvalue = Wire.read(); 227 | if (Par2 == 1) 228 | portvalue |= (1 << (port - 1)); 229 | else 230 | portvalue &= ~(1 << (port - 1)); 231 | 232 | // write new IO config 233 | Wire.beginTransmission(address); 234 | Wire.write(IOBankConfigReg); // IO config register 235 | Wire.write(portvalue); 236 | Wire.endTransmission(); 237 | } 238 | } 239 | 240 | -------------------------------------------------------------------------------- /_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 0x23 11 | boolean Plugin_010_init = false; 12 | 13 | boolean Plugin_010(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success=false; 16 | 17 | switch(function) 18 | { 19 | 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | Device[++deviceCount].Number = PLUGIN_ID_010; 23 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 24 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 25 | Device[deviceCount].Ports = 0; 26 | Device[deviceCount].PullUpOption = false; 27 | Device[deviceCount].InverseLogicOption = false; 28 | Device[deviceCount].ValueCount = 1; 29 | Device[deviceCount].SendDataOption = true; 30 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_010); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_010)); 42 | break; 43 | } 44 | 45 | case PLUGIN_READ: 46 | { 47 | if (!Plugin_010_init) 48 | { 49 | Plugin_010_init=true; 50 | Wire.beginTransmission(BH1750_ADDRESS); 51 | Wire.write(0x10); // 1 lx resolution 52 | Wire.endTransmission(); 53 | } 54 | Wire.requestFrom(BH1750_ADDRESS, 2); 55 | byte b1 = Wire.read(); 56 | byte b2 = Wire.read(); 57 | float val=0; 58 | val=((b1<<8)|b2)/1.2; 59 | UserVar[event->BaseVarIndex] = val; 60 | String log = F("LUX : Light intensity: "); 61 | log += UserVar[event->BaseVarIndex]; 62 | addLog(LOG_LEVEL_INFO,log); 63 | success=true; 64 | break; 65 | } 66 | } 67 | return success; 68 | } 69 | -------------------------------------------------------------------------------- /_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 | boolean Plugin_011(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_011; 20 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 21 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = true; 25 | Device[deviceCount].Ports = 14; 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_011); 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICEVALUENAMES: 38 | { 39 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_011)); 40 | break; 41 | } 42 | 43 | case PLUGIN_WEBFORM_LOAD: 44 | { 45 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 46 | String options[2]; 47 | options[0] = F("Digital"); 48 | options[1] = F("Analog"); 49 | int optionValues[2]; 50 | optionValues[0] = 0; 51 | optionValues[1] = 1; 52 | string += F("Port Type:"); 65 | 66 | success = true; 67 | break; 68 | } 69 | 70 | case PLUGIN_WEBFORM_SAVE: 71 | { 72 | String plugin1 = WebServer.arg("plugin_011"); 73 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 74 | success = true; 75 | break; 76 | } 77 | 78 | case PLUGIN_READ: 79 | { 80 | uint8_t address = 0x7f; 81 | Wire.beginTransmission(address); 82 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 0) 83 | Wire.write(2); // Digital Read 84 | else 85 | Wire.write(4); // Analog Read 86 | Wire.write(Settings.TaskDevicePort[event->TaskIndex]); 87 | Wire.write(0); 88 | Wire.write(0); 89 | Wire.endTransmission(); 90 | delay(1); // remote unit needs some time for conversion... 91 | Wire.requestFrom(address, (uint8_t)0x4); 92 | byte buffer[4]; 93 | if (Wire.available() == 4) 94 | { 95 | for (byte x=0; x < 4; x++) 96 | buffer[x]=Wire.read(); 97 | UserVar[event->BaseVarIndex] = buffer[0] + 256 * buffer[1]; 98 | } 99 | String log = F("PME : PortValue: "); 100 | log += UserVar[event->BaseVarIndex]; 101 | addLog(LOG_LEVEL_INFO,log); 102 | success = true; 103 | break; 104 | } 105 | 106 | case PLUGIN_WRITE: 107 | { 108 | String tmpString = string; 109 | int argIndex = tmpString.indexOf(','); 110 | if (argIndex) 111 | tmpString = tmpString.substring(0, argIndex); 112 | if (tmpString.equalsIgnoreCase("EXTGPIO")) 113 | { 114 | success = true; 115 | uint8_t address = 0x7f; 116 | Wire.beginTransmission(address); 117 | Wire.write(1); 118 | Wire.write(event->Par1); 119 | Wire.write(event->Par2 & 0xff); 120 | Wire.write((event->Par2 >> 8)); 121 | Wire.endTransmission(); 122 | if (printToWeb) 123 | { 124 | printWebString += F("EXTGPIO "); 125 | printWebString += event->Par1; 126 | printWebString += F(" Set to "); 127 | printWebString += event->Par2; 128 | printWebString += F("
"); 129 | } 130 | } 131 | 132 | if (tmpString.equalsIgnoreCase("EXTPWM")) 133 | { 134 | success = true; 135 | uint8_t address = 0x7f; 136 | Wire.beginTransmission(address); 137 | Wire.write(3); 138 | Wire.write(event->Par1); 139 | Wire.write(event->Par2 & 0xff); 140 | Wire.write((event->Par2 >> 8)); 141 | Wire.endTransmission(); 142 | if (printToWeb) 143 | { 144 | printWebString += F("EXTPWM "); 145 | printWebString += event->Par1; 146 | printWebString += F(" Set to "); 147 | printWebString += event->Par2; 148 | printWebString += F("
"); 149 | } 150 | } 151 | break; 152 | } 153 | } 154 | return success; 155 | } 156 | -------------------------------------------------------------------------------- /_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 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICENAME: 41 | { 42 | string = F(PLUGIN_NAME_012); 43 | break; 44 | } 45 | 46 | case PLUGIN_GET_DEVICEVALUENAMES: 47 | { 48 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_012)); 49 | break; 50 | } 51 | 52 | case PLUGIN_WEBFORM_LOAD: 53 | { 54 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 55 | int optionValues[16]; 56 | for (byte x = 0; x < 17; x++) 57 | if (x < 8) 58 | optionValues[x] = 0x20 + x; 59 | else 60 | optionValues[x] = 0x30 + x; 61 | 62 | string += F("I2C Address:"); 75 | 76 | byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 77 | String options2[2]; 78 | options2[0] = F("2 x 16"); 79 | options2[1] = F("4 x 20"); 80 | int optionValues2[2]; 81 | optionValues2[0] = 1; 82 | optionValues2[1] = 2; 83 | string += F("Display Size:"); 96 | 97 | char deviceTemplate[4][80]; 98 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 99 | for (byte varNr = 0; varNr < 4; varNr++) 100 | { 101 | string += F("Line "); 102 | string += varNr + 1; 103 | string += F(":"); 108 | } 109 | 110 | string += F("Display button:"); 111 | addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]); 112 | 113 | char tmpString[128]; 114 | 115 | sprintf_P(tmpString, PSTR("Display Timeout:"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]); 116 | string += tmpString; 117 | 118 | success = true; 119 | break; 120 | } 121 | 122 | case PLUGIN_WEBFORM_SAVE: 123 | { 124 | String plugin1 = WebServer.arg("plugin_012_adr"); 125 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 126 | String plugin2 = WebServer.arg("plugin_012_size"); 127 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 128 | String plugin3 = WebServer.arg("plugin_12_timer"); 129 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); 130 | 131 | char deviceTemplate[4][80]; 132 | for (byte varNr = 0; varNr < 4; varNr++) 133 | { 134 | char argc[25]; 135 | String arg = F("Plugin_012_template"); 136 | arg += varNr + 1; 137 | arg.toCharArray(argc, 25); 138 | String tmpString = WebServer.arg(argc); 139 | strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])); 140 | } 141 | 142 | Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value 143 | 144 | SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 145 | success = true; 146 | break; 147 | } 148 | 149 | case PLUGIN_INIT: 150 | { 151 | if (!lcd) 152 | { 153 | byte row = 2; 154 | byte col = 16; 155 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 156 | { 157 | row = 4; 158 | col = 20; 159 | } 160 | lcd = new LiquidCrystal_I2C(Settings.TaskDevicePluginConfig[event->TaskIndex][0], col, row); 161 | } 162 | // Setup LCD display 163 | lcd->init(); // initialize the lcd 164 | lcd->backlight(); 165 | lcd->print("ESP Easy"); 166 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 167 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 168 | pinMode(Settings.TaskDevicePin3[event->TaskIndex], INPUT_PULLUP); 169 | success = true; 170 | break; 171 | } 172 | 173 | case PLUGIN_TEN_PER_SECOND: 174 | { 175 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 176 | { 177 | if (!digitalRead(Settings.TaskDevicePin3[event->TaskIndex])) 178 | { 179 | lcd->backlight(); 180 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 181 | } 182 | } 183 | break; 184 | } 185 | 186 | case PLUGIN_ONCE_A_SECOND: 187 | { 188 | if ( displayTimer > 0) 189 | { 190 | displayTimer--; 191 | if (displayTimer == 0) 192 | lcd->noBacklight(); 193 | } 194 | break; 195 | } 196 | 197 | case PLUGIN_READ: 198 | { 199 | char deviceTemplate[4][80]; 200 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 201 | 202 | byte row = 2; 203 | byte col = 16; 204 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 205 | { 206 | row = 4; 207 | col = 20; 208 | } 209 | 210 | for (byte x = 0; x < row; x++) 211 | { 212 | String tmpString = deviceTemplate[x]; 213 | if (tmpString.length()) 214 | { 215 | String newString = parseTemplate(tmpString, col); 216 | lcd->setCursor(0, x); 217 | lcd->print(newString); 218 | } 219 | } 220 | success = false; 221 | break; 222 | } 223 | 224 | case PLUGIN_WRITE: 225 | { 226 | String tmpString = string; 227 | int argIndex = tmpString.indexOf(','); 228 | if (argIndex) 229 | tmpString = tmpString.substring(0, argIndex); 230 | if (tmpString.equalsIgnoreCase("LCD")) 231 | { 232 | success = true; 233 | argIndex = string.lastIndexOf(','); 234 | tmpString = string.substring(argIndex + 1); 235 | lcd->setCursor(event->Par2 - 1, event->Par1 - 1); 236 | lcd->print(tmpString.c_str()); 237 | } 238 | if (tmpString.equalsIgnoreCase("LCDCMD")) 239 | { 240 | success = true; 241 | argIndex = string.lastIndexOf(','); 242 | tmpString = string.substring(argIndex + 1); 243 | if (tmpString.equalsIgnoreCase("Off")) 244 | lcd->noBacklight(); 245 | else if (tmpString.equalsIgnoreCase("On")) 246 | lcd->backlight(); 247 | else if (tmpString.equalsIgnoreCase("Clear")) 248 | lcd->clear(); 249 | } 250 | break; 251 | } 252 | 253 | } 254 | return success; 255 | } 256 | -------------------------------------------------------------------------------- /_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 | boolean Plugin_013_init = false; 11 | volatile unsigned long Plugin_013_timer = 0; 12 | volatile unsigned long Plugin_013_state = 0; 13 | byte Plugin_013_TRIG_Pin = 0; 14 | byte Plugin_013_IRQ_Pin = 0; 15 | 16 | boolean Plugin_013(byte function, struct EventStruct *event, String& string) 17 | { 18 | static byte switchstate[TASKS_MAX]; 19 | boolean success = false; 20 | 21 | switch (function) 22 | { 23 | case PLUGIN_DEVICE_ADD: 24 | { 25 | Device[++deviceCount].Number = PLUGIN_ID_013; 26 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 27 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 28 | Device[deviceCount].Ports = 0; 29 | Device[deviceCount].PullUpOption = false; 30 | Device[deviceCount].InverseLogicOption = false; 31 | Device[deviceCount].FormulaOption = false; 32 | Device[deviceCount].ValueCount = 1; 33 | Device[deviceCount].SendDataOption = true; 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICENAME: 38 | { 39 | string = F(PLUGIN_NAME_013); 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICEVALUENAMES: 44 | { 45 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_013)); 46 | break; 47 | } 48 | 49 | 50 | case PLUGIN_WEBFORM_LOAD: 51 | { 52 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 53 | String options[2]; 54 | options[0] = F("Value"); 55 | options[1] = F("State"); 56 | int optionValues[2]; 57 | optionValues[0] = 1; 58 | optionValues[1] = 2; 59 | string += F("Mode:"); 72 | 73 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 74 | { 75 | char tmpString[128]; 76 | sprintf_P(tmpString, PSTR("Threshold:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 77 | string += tmpString; 78 | } 79 | success = true; 80 | break; 81 | } 82 | 83 | case PLUGIN_WEBFORM_SAVE: 84 | { 85 | String plugin1 = WebServer.arg("plugin_013_mode"); 86 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 87 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 88 | { 89 | String plugin2 = WebServer.arg("plugin_013_threshold"); 90 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 91 | } 92 | success = true; 93 | break; 94 | } 95 | 96 | case PLUGIN_INIT: 97 | { 98 | Plugin_013_init = true; 99 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 100 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 101 | Plugin_013_IRQ_Pin = Settings.TaskDevicePin2[event->TaskIndex]; 102 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_013_interrupt, CHANGE); 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_READ: // If we select value mode, read and send the value based on global timer 108 | { 109 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1) 110 | { 111 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 112 | float value = Plugin_013_read(); 113 | String log = F("SR04 : Distance: "); 114 | if (value != -1) 115 | { 116 | UserVar[event->BaseVarIndex] = (float)Plugin_013_timer / 58; 117 | log += UserVar[event->BaseVarIndex]; 118 | success = true; 119 | } 120 | else 121 | log += F("SR04 : Distance: No reading!"); 122 | 123 | addLog(LOG_LEVEL_INFO,log); 124 | } 125 | break; 126 | } 127 | 128 | case PLUGIN_TEN_PER_SECOND: // If we select state mode, do more frequent checks and send only state changes 129 | { 130 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 131 | { 132 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 133 | byte state = 0; 134 | float value = Plugin_013_read(); 135 | if (value != -1) 136 | { 137 | if (value < Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 138 | state = 1; 139 | if (state != switchstate[event->TaskIndex]) 140 | { 141 | String log = F("SR04 : State "); 142 | log += state; 143 | addLog(LOG_LEVEL_INFO,log); 144 | switchstate[event->TaskIndex] = state; 145 | UserVar[event->BaseVarIndex] = state; 146 | event->sensorType = SENSOR_TYPE_SWITCH; 147 | sendData(event); 148 | } 149 | } 150 | } 151 | success = true; 152 | break; 153 | } 154 | } 155 | return success; 156 | } 157 | 158 | /*********************************************************************/ 159 | float Plugin_013_read() 160 | /*********************************************************************/ 161 | { 162 | float value = -1; 163 | Plugin_013_timer = 0; 164 | Plugin_013_state = 0; 165 | noInterrupts(); 166 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 167 | delayMicroseconds(2); 168 | digitalWrite(Plugin_013_TRIG_Pin, HIGH); 169 | delayMicroseconds(10); 170 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 171 | interrupts(); 172 | 173 | delay(25); // wait for measurement to finish (max 400 cm * 58 uSec = 23uSec) 174 | if (Plugin_013_state == 2) 175 | { 176 | value = (float)Plugin_013_timer / 58; 177 | } 178 | return value; 179 | } 180 | 181 | /*********************************************************************/ 182 | void Plugin_013_interrupt() 183 | /*********************************************************************/ 184 | { 185 | byte pinState = digitalRead(Plugin_013_IRQ_Pin); 186 | if (pinState == 1) // Start of pulse 187 | { 188 | Plugin_013_state = 1; 189 | Plugin_013_timer = micros(); 190 | } 191 | else // End of pulse, calculate timelapse between start & end 192 | { 193 | Plugin_013_state = 2; 194 | Plugin_013_timer = micros() - Plugin_013_timer; 195 | } 196 | } 197 | 198 | -------------------------------------------------------------------------------- /_P015_TLS2561.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 015 TSL2561 I2C Lux Sensor ############################################ 3 | //####################################################################################################### 4 | // 13-10-2015 Charles-Henri Hallard, see my projects and blog at https://hallard.me 5 | 6 | #define PLUGIN_015 7 | #define PLUGIN_ID_015 15 8 | #define PLUGIN_NAME_015 "Luminosity - TLS2561" 9 | #define PLUGIN_VALUENAME1_015 "Lux" 10 | 11 | boolean Plugin_015_init = false; 12 | 13 | // ====================================== 14 | // TSL2561 luminosity sensor 15 | // ====================================== 16 | #define TSL2561_I2C_ADDRESS 0x39 // I2C address for the sensor 17 | #define TSL2561_CONTROL 0x80 18 | #define TSL2561_TIMING 0x81 19 | #define TSL2561_INTERRUPT 0x86 20 | #define TSL2561_CHANNEL_0L 0x8C 21 | #define TSL2561_CHANNEL_0H 0x8D 22 | #define TSL2561_CHANNEL_1L 0x8E 23 | #define TSL2561_CHANNEL_1H 0x8F 24 | 25 | // Control register bits 26 | #define TSL2561_POWER_UP 0x03 27 | #define TSL2561_POWER_DOWN 0x00 28 | 29 | // Timing register bits 30 | #define TSL2561_TIMING_13MS 0x00 31 | #define TSL2561_TIMING_101MS 0x01 32 | #define TSL2561_TIMING_402MS 0x02 33 | #define TSL2561_TIMING_CUSTOM_STOP 0x03 34 | #define TSL2561_TIMING_CUSTOM_START 0x0B 35 | 36 | #define TSL2561_LUX_SCALE 14 // scale by 2^14 37 | #define TSL2561_RATIO_SCALE 9 // scale ratio by 2^9 38 | #define TSL2561_CH_SCALE 10 // scale channel values by 2^10 39 | #define TSL2561_CHSCALE_TINT_13MS 0x7517 // 322/11 * 2^CH_SCALE (13ms) 40 | #define TSL2561_CHSCALE_TINT_60MS 0x1800 // 322/48 * 2^CH_SCALE (60ms) 41 | #define TSL2561_CHSCALE_TINT_101MS 0x0fe7 // 322/81 * 2^CH_SCALE (101ms) 42 | #define TSL2561_CHSCALE_TINT_120MS 0x0D6B // 322/96 * 2^CH_SCALE (120ms) 43 | #define TSL2561_CHSCALE_TINT_402MS (1 << TSL2561_CH_SCALE) // default No scaling 44 | 45 | // Clipping thresholds 46 | #define TSL2561_CLIPPING_13MS (4900) 47 | #define TSL2561_CLIPPING_101MS (37000) 48 | #define TSL2561_CLIPPING_402MS (65000) 49 | 50 | #define TSL2561_K1T 0x0040 // 0.125 * 2^RATIO_SCALE 51 | #define TSL2561_B1T 0x01f2 // 0.0304 * 2^LUX_SCALE 52 | #define TSL2561_M1T 0x01be // 0.0272 * 2^LUX_SCALE 53 | #define TSL2561_K2T 0x0080 // 0.250 * 2^RATIO_SCA 54 | #define TSL2561_B2T 0x0214 // 0.0325 * 2^LUX_SCALE 55 | #define TSL2561_M2T 0x02d1 // 0.0440 * 2^LUX_SCALE 56 | #define TSL2561_K3T 0x00c0 // 0.375 * 2^RATIO_SCALE 57 | #define TSL2561_B3T 0x023f // 0.0351 * 2^LUX_SCALE 58 | #define TSL2561_M3T 0x037b // 0.0544 * 2^LUX_SCALE 59 | #define TSL2561_K4T 0x0100 // 0.50 * 2^RATIO_SCALE 60 | #define TSL2561_B4T 0x0270 // 0.0381 * 2^LUX_SCALE 61 | #define TSL2561_M4T 0x03fe // 0.0624 * 2^LUX_SCALE 62 | #define TSL2561_K5T 0x0138 // 0.61 * 2^RATIO_SCALE 63 | #define TSL2561_B5T 0x016f // 0.0224 * 2^LUX_SCALE 64 | #define TSL2561_M5T 0x01fc // 0.0310 * 2^LUX_SCALE 65 | #define TSL2561_K6T 0x019a // 0.80 * 2^RATIO_SCALE 66 | #define TSL2561_B6T 0x00d2 // 0.0128 * 2^LUX_SCALE 67 | #define TSL2561_M6T 0x00fb // 0.0153 * 2^LUX_SCALE 68 | #define TSL2561_K7T 0x029a // 1.3 * 2^RATIO_SCALE 69 | #define TSL2561_B7T 0x0018 // 0.00146 * 2^LUX_SCALE 70 | #define TSL2561_M7T 0x0012 // 0.00112 * 2^LUX_SCALE 71 | #define TSL2561_K8T 0x029a // 1.3 * 2^RATIO_SCALE 72 | #define TSL2561_B8T 0x0000 // 0.000 * 2^LUX_SCALE 73 | #define TSL2561_M8T 0x0000 // 0.000 * 2^LUX_SCALE 74 | 75 | 76 | uint16_t tsl2561_lux; // latest lux value read 77 | 78 | boolean Plugin_015(byte function, struct EventStruct *event, String& string) 79 | { 80 | boolean success = false; 81 | 82 | switch (function) 83 | { 84 | case PLUGIN_DEVICE_ADD: 85 | { 86 | Device[++deviceCount].Number = PLUGIN_ID_015; 87 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 88 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 89 | Device[deviceCount].Ports = 0; 90 | Device[deviceCount].PullUpOption = false; 91 | Device[deviceCount].InverseLogicOption = false; 92 | Device[deviceCount].FormulaOption = true; 93 | Device[deviceCount].ValueCount = 1; 94 | Device[deviceCount].SendDataOption = true; 95 | break; 96 | } 97 | 98 | case PLUGIN_GET_DEVICENAME: 99 | { 100 | string = F(PLUGIN_NAME_015); 101 | break; 102 | } 103 | 104 | case PLUGIN_GET_DEVICEVALUENAMES: 105 | { 106 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_015)); 107 | break; 108 | } 109 | 110 | case PLUGIN_WEBFORM_LOAD: 111 | { 112 | #define TLS2561_INTEGRATION_OPTION 3 113 | 114 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 115 | String options[TLS2561_INTEGRATION_OPTION]; 116 | int optionValues[TLS2561_INTEGRATION_OPTION]; 117 | optionValues[0] = TSL2561_TIMING_13MS; 118 | options[0] = F("13 ms"); 119 | optionValues[1] = TSL2561_TIMING_101MS; 120 | options[1] = F("101 ms"); 121 | optionValues[2] = TSL2561_TIMING_402MS; 122 | options[2] = F("402 ms"); 123 | 124 | string += F("Integration time:"); 137 | 138 | success = true; 139 | break; 140 | } 141 | 142 | case PLUGIN_WEBFORM_SAVE: 143 | { 144 | String plugin1 = WebServer.arg("plugin_015_integration"); 145 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 146 | Plugin_015_init = false; // Force device setup next time 147 | success = true; 148 | break; 149 | } 150 | 151 | case PLUGIN_READ: 152 | { 153 | // Get sensor resolution configuration 154 | uint8_t integration = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 155 | uint8_t ret; 156 | 157 | if (!Plugin_015_init) { 158 | Plugin_015_init = Plugin_015_tls2561_begin(integration); 159 | } 160 | 161 | // Read values if init ok 162 | if (Plugin_015_init) { 163 | ret = Plugin_015_tsl2561_calcLux(integration); 164 | if (ret == 0) { 165 | UserVar[event->BaseVarIndex] = tsl2561_lux; 166 | success = true; 167 | String log = F("TLS2561 : Lux: "); 168 | log += UserVar[event->BaseVarIndex]; 169 | addLog(LOG_LEVEL_INFO,log); 170 | } else { 171 | String log = F("TLS2561 : Read Error #"); 172 | log += String(ret,DEC); 173 | addLog(LOG_LEVEL_INFO,log); 174 | } 175 | } 176 | break; 177 | } 178 | 179 | } 180 | return success; 181 | } 182 | 183 | /* ====================================================================== 184 | Function: Plugin_015_tls2561_begin 185 | Purpose : read the user register from the sensor 186 | Input : integration time 187 | Output : true if okay 188 | Comments: - 189 | ====================================================================== */ 190 | boolean Plugin_015_tls2561_begin(uint8_t integration) 191 | { 192 | uint8_t ret; 193 | 194 | // Power UP device 195 | ret = Plugin_015_tsl2561_writeRegister(TSL2561_CONTROL, TSL2561_POWER_UP); 196 | if ( ret == 0 ) 197 | { 198 | // I noticed 1st calculation after power up could be hazardous; so 199 | // do a 1st dummy reading, with speed integration time, here 13ms 200 | Plugin_015_tsl2561_writeRegister(TSL2561_TIMING, TSL2561_TIMING_13MS); 201 | delay(15); 202 | ret = true; 203 | } else { 204 | String log = F("TLS2561 : integration=0x"); 205 | log += String(integration,HEX); 206 | log += F(" => Error 0x"); 207 | log += String(ret,HEX); 208 | addLog(LOG_LEVEL_INFO,log); 209 | ret = false; 210 | } 211 | 212 | return ret; 213 | } 214 | 215 | /* ====================================================================== 216 | Function: Plugin_015_tsl2561_readRegister 217 | Purpose : read a register from the sensor 218 | Input : register address 219 | register value filled by function 220 | Output : 0 if okay 221 | Comments: - 222 | ====================================================================== */ 223 | uint8_t Plugin_015_tsl2561_readRegister(uint8_t reg, uint8_t * value) 224 | { 225 | Wire.beginTransmission(TSL2561_I2C_ADDRESS); 226 | Wire.write(reg); 227 | // all was fine ? 228 | if ( Wire.endTransmission()==0 ) { 229 | // request 1 byte and have it ? 230 | if (Wire.requestFrom(TSL2561_I2C_ADDRESS, 1)==1) { 231 | // return value 232 | *value = Wire.read(); 233 | return 0; 234 | } 235 | } 236 | return 1; 237 | } 238 | 239 | /* ====================================================================== 240 | Function: Plugin_015_tsl2561_writeRegister 241 | Purpose : read a register from the sensor 242 | Input : register address 243 | Output : register value 244 | Comments: 0 if okay 245 | ====================================================================== */ 246 | uint8_t Plugin_015_tsl2561_writeRegister(uint8_t reg, uint8_t value) 247 | { 248 | Wire.beginTransmission(TSL2561_I2C_ADDRESS); 249 | Wire.write(reg); 250 | Wire.write(value); 251 | return (Wire.endTransmission()); 252 | } 253 | 254 | /* ====================================================================== 255 | Function: Plugin_015_tsl2561_calcLux 256 | Purpose : start a conversion and return calculated lux 257 | Input : integration time 258 | Output : 0 if calculated value ok and updated 259 | Comments: global lux value is updated 260 | ====================================================================== */ 261 | int8_t Plugin_015_tsl2561_calcLux(uint8_t integration) 262 | { 263 | unsigned long chScale; 264 | unsigned long channel0, channel1; 265 | unsigned long ratio, ratio1; 266 | unsigned long lux; 267 | unsigned int b, m; 268 | uint16_t ch0,ch1; 269 | uint16_t clipThreshold; 270 | uint8_t msb, lsb; 271 | uint8_t err = 0; 272 | 273 | // do start calculation with speed integration time, 274 | Plugin_015_tsl2561_writeRegister(TSL2561_TIMING, integration); 275 | if (integration == TSL2561_TIMING_402MS ) { 276 | chScale = TSL2561_CHSCALE_TINT_402MS ; 277 | clipThreshold = TSL2561_CLIPPING_402MS ; 278 | delay(405); 279 | } else if (integration == TSL2561_TIMING_101MS ) { 280 | chScale = TSL2561_CHSCALE_TINT_101MS ; 281 | clipThreshold = TSL2561_CLIPPING_101MS ; 282 | delay(103); 283 | } else { 284 | chScale = TSL2561_CHSCALE_TINT_13MS ; 285 | clipThreshold = TSL2561_CLIPPING_13MS ; 286 | delay(15); 287 | } 288 | 289 | // don't try to change reading order of LOW/HIGH, it will not work !!!! 290 | // you must read LOW then HIGH 291 | err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_0L, &lsb); 292 | err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_0H, &msb); 293 | ch0 = word(msb,lsb); 294 | err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_1L, &lsb); 295 | err |= Plugin_015_tsl2561_readRegister(TSL2561_CHANNEL_1H, &msb); 296 | ch1 = word(msb,lsb);; 297 | 298 | // I2C error ? 299 | if( err ) 300 | return -2; 301 | 302 | /* Sensor saturated the lux is not valid in this situation */ 303 | if ((ch0 > clipThreshold) || (ch1 > clipThreshold)) 304 | { 305 | return -1; 306 | } 307 | 308 | // gain is 1 so put it to 16X 309 | chScale <<= 4; 310 | 311 | // scale the channel values 312 | channel0 = (ch0 * chScale) >> TSL2561_CH_SCALE; 313 | channel1 = (ch1 * chScale) >> TSL2561_CH_SCALE; 314 | 315 | ratio1 = 0; 316 | if (channel0!= 0) 317 | ratio1 = (channel1 << (TSL2561_RATIO_SCALE+1))/channel0; 318 | 319 | // round the ratio value 320 | ratio = (ratio1 + 1) >> 1; 321 | 322 | // ULPNode have T package 323 | // Adjust constant depending on calculated ratio 324 | if ((ratio >= 0) && (ratio <= TSL2561_K1T)) 325 | {b=TSL2561_B1T; m=TSL2561_M1T;} 326 | else if (ratio <= TSL2561_K2T) 327 | {b=TSL2561_B2T; m=TSL2561_M2T;} 328 | else if (ratio <= TSL2561_K3T) 329 | {b=TSL2561_B3T; m=TSL2561_M3T;} 330 | else if (ratio <= TSL2561_K4T) 331 | {b=TSL2561_B4T; m=TSL2561_M4T;} 332 | else if (ratio <= TSL2561_K5T) 333 | {b=TSL2561_B5T; m=TSL2561_M5T;} 334 | else if (ratio <= TSL2561_K6T) 335 | {b=TSL2561_B6T; m=TSL2561_M6T;} 336 | else if (ratio <= TSL2561_K7T) 337 | {b=TSL2561_B7T; m=TSL2561_M7T;} 338 | else if (ratio > TSL2561_K8T) 339 | {b=TSL2561_B8T; m=TSL2561_M8T;} 340 | 341 | // datasheet formula 342 | lux=((channel0*b)-(channel1*m)); 343 | 344 | // do not allow negative lux value 345 | if(lux<0) 346 | lux=0; 347 | 348 | // round lsb (2^(LUX_SCALE−1)) 349 | lux += (1<<(TSL2561_LUX_SCALE-1)); 350 | 351 | // strip off fractional portion 352 | lux >>= TSL2561_LUX_SCALE; 353 | 354 | // strip off fractional portion 355 | tsl2561_lux = (uint16_t) (lux); 356 | 357 | return 0; 358 | } 359 | -------------------------------------------------------------------------------- /_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 input - 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_SINGLE; 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 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_016); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_016)); 43 | break; 44 | } 45 | 46 | case PLUGIN_INIT: 47 | { 48 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 49 | if (irReceiver == 0 && irPin != -1) 50 | { 51 | Serial.println("IR Init"); 52 | irReceiver= new IRrecv(irPin); 53 | irReceiver->enableIRIn(); // Start the receiver 54 | } 55 | if (irReceiver != 0 && irPin == -1) 56 | { 57 | Serial.println("IR Removed"); 58 | irReceiver->disableIRIn(); 59 | delete irReceiver; 60 | irReceiver=0; 61 | } 62 | success = true; 63 | break; 64 | } 65 | 66 | case PLUGIN_TEN_PER_SECOND: 67 | { 68 | if (irReceiver->decode(&results)) 69 | { 70 | unsigned long IRcode = results.value; 71 | irReceiver->resume(); 72 | UserVar[event->BaseVarIndex] = IRcode; 73 | String log = F("IR : Code "); 74 | log += String(IRcode, HEX); 75 | addLog(LOG_LEVEL_INFO, log); 76 | sendData(event); 77 | } 78 | success = true; 79 | break; 80 | } 81 | } 82 | return success; 83 | } 84 | 85 | -------------------------------------------------------------------------------- /_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 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_018); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_018)); 42 | break; 43 | } 44 | 45 | case PLUGIN_INIT: 46 | { 47 | Plugin_018_init = true; 48 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 49 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 50 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 51 | success = true; 52 | break; 53 | } 54 | 55 | 56 | case PLUGIN_READ: 57 | { 58 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 59 | noInterrupts(); 60 | byte x; 61 | int value; 62 | value = 0; 63 | for (x = 0; x < 25; x++) 64 | { 65 | digitalWrite(Plugin_GP2Y10_LED_Pin, LOW); 66 | delayMicroseconds(280); 67 | value = value + analogRead(A0); 68 | delayMicroseconds(40); 69 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 70 | delayMicroseconds(9680); 71 | } 72 | interrupts(); 73 | UserVar[event->BaseVarIndex] = (float)value; 74 | String log = F("GPY : Dust value: "); 75 | log += value; 76 | addLog(LOG_LEVEL_INFO, log); 77 | success = true; 78 | break; 79 | } 80 | } 81 | return success; 82 | } 83 | -------------------------------------------------------------------------------- /_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 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_019); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_019)); 41 | break; 42 | } 43 | 44 | case PLUGIN_INIT: 45 | { 46 | // read and store current state to prevent switching at boot time 47 | switchstate[event->TaskIndex] = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 48 | success = true; 49 | break; 50 | } 51 | 52 | case PLUGIN_TEN_PER_SECOND: 53 | { 54 | int state = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 55 | if (state != -1) 56 | { 57 | if (state != switchstate[event->TaskIndex]) 58 | { 59 | String log = F("PCF : State "); 60 | log += state; 61 | addLog(LOG_LEVEL_INFO,log); 62 | switchstate[event->TaskIndex] = state; 63 | UserVar[event->BaseVarIndex] = state; 64 | event->sensorType = SENSOR_TYPE_SWITCH; 65 | sendData(event); 66 | } 67 | } 68 | success = true; 69 | break; 70 | } 71 | 72 | case PLUGIN_WRITE: 73 | { 74 | String tmpString = string; 75 | int argIndex = tmpString.indexOf(','); 76 | if (argIndex) 77 | tmpString = tmpString.substring(0, argIndex); 78 | if (tmpString.equalsIgnoreCase("PCFGPIO")) 79 | { 80 | success = true; 81 | Plugin_019_Write(event->Par1, event->Par2); 82 | if (printToWeb) 83 | { 84 | printWebString += F("PCFGPIO "); 85 | printWebString += event->Par1; 86 | printWebString += F(" Set to "); 87 | printWebString += event->Par2; 88 | printWebString += F("
"); 89 | } 90 | } 91 | break; 92 | } 93 | } 94 | return success; 95 | } 96 | 97 | 98 | //******************************************************************************** 99 | // PCF8574 read 100 | //******************************************************************************** 101 | int Plugin_019_Read(byte Par1) 102 | { 103 | int8_t state = -1; 104 | byte unit = (Par1 - 1) / 8; 105 | byte port = Par1 - (unit * 8); 106 | uint8_t address = 0x20 + unit; 107 | if (unit > 7) address += 0x10; 108 | 109 | // get the current pin status 110 | Wire.requestFrom(address, (uint8_t)0x1); 111 | if (Wire.available()) 112 | { 113 | state = ((Wire.read() & _BV(port - 1)) >> (port - 1)); 114 | } 115 | return state; 116 | } 117 | 118 | 119 | //******************************************************************************** 120 | // PCF8574 write 121 | //******************************************************************************** 122 | boolean Plugin_019_Write(byte Par1, byte Par2) 123 | { 124 | boolean success = false; 125 | byte portvalue = 0; 126 | byte unit = (Par1 - 1) / 8; 127 | byte port = Par1 - (unit * 8); 128 | uint8_t address = 0x20 + unit; 129 | if (unit > 7) address += 0x10; 130 | 131 | // get the current pin status 132 | Wire.requestFrom(address, (uint8_t)0x1); 133 | if (Wire.available()) 134 | { 135 | portvalue = Wire.read(); 136 | if (Par2 == 1) 137 | portvalue |= (1 << (port - 1)); 138 | else 139 | portvalue &= ~(1 << (port - 1)); 140 | 141 | // write back new data 142 | Wire.beginTransmission(address); 143 | Wire.write(portvalue); 144 | Wire.endTransmission(); 145 | success = true; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /_P020_Ser2Net.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 020: Ser2Net ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_020 6 | #define PLUGIN_ID_020 20 7 | #define PLUGIN_NAME_020 "Serial Server" 8 | #define PLUGIN_VALUENAME1_020 "Ser2Net" 9 | 10 | #define BUFFER_SIZE 128 11 | boolean Plugin_020_init = false; 12 | 13 | WiFiServer *ser2netServer; 14 | WiFiClient ser2netClient; 15 | 16 | boolean Plugin_020(byte function, struct EventStruct *event, String& string) 17 | { 18 | boolean success = false; 19 | 20 | switch (function) 21 | { 22 | 23 | case PLUGIN_DEVICE_ADD: 24 | { 25 | Device[++deviceCount].Number = PLUGIN_ID_020; 26 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 27 | Device[deviceCount].Custom = true; 28 | break; 29 | } 30 | 31 | case PLUGIN_GET_DEVICENAME: 32 | { 33 | string = F(PLUGIN_NAME_020); 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICEVALUENAMES: 38 | { 39 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_020)); 40 | break; 41 | } 42 | 43 | case PLUGIN_WEBFORM_LOAD: 44 | { 45 | char tmpString[128]; 46 | sprintf_P(tmpString, PSTR("TCP Port:"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]); 47 | string += tmpString; 48 | sprintf_P(tmpString, PSTR("Baud Rate:"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]); 49 | string += tmpString; 50 | sprintf_P(tmpString, PSTR("Data bits:"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]); 51 | string += tmpString; 52 | 53 | byte choice = ExtraTaskSettings.TaskDevicePluginConfigLong[3]; 54 | String options[3]; 55 | options[0] = F("No parity"); 56 | options[1] = F("Even"); 57 | options[2] = F("Odd"); 58 | int optionValues[3]; 59 | optionValues[0] = 0; 60 | optionValues[1] = 2; 61 | optionValues[2] = 3; 62 | string += F("Parity:"); 75 | 76 | sprintf_P(tmpString, PSTR("Stop bits:"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]); 77 | string += tmpString; 78 | 79 | string += F("Reset target after boot:"); 80 | addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]); 81 | 82 | success = true; 83 | break; 84 | } 85 | 86 | case PLUGIN_WEBFORM_SAVE: 87 | { 88 | String plugin1 = WebServer.arg("plugin_020_port"); 89 | ExtraTaskSettings.TaskDevicePluginConfigLong[0] = plugin1.toInt(); 90 | String plugin2 = WebServer.arg("plugin_020_baud"); 91 | ExtraTaskSettings.TaskDevicePluginConfigLong[1] = plugin2.toInt(); 92 | String plugin3 = WebServer.arg("plugin_020_data"); 93 | ExtraTaskSettings.TaskDevicePluginConfigLong[2] = plugin3.toInt(); 94 | String plugin4 = WebServer.arg("plugin_020_parity"); 95 | ExtraTaskSettings.TaskDevicePluginConfigLong[3] = plugin4.toInt(); 96 | String plugin5 = WebServer.arg("plugin_020_stop"); 97 | ExtraTaskSettings.TaskDevicePluginConfigLong[4] = plugin5.toInt(); 98 | SaveTaskSettings(event->TaskIndex); 99 | success = true; 100 | break; 101 | } 102 | 103 | case PLUGIN_INIT: 104 | { 105 | LoadTaskSettings(event->TaskIndex); 106 | if ((ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0) && (ExtraTaskSettings.TaskDevicePluginConfigLong[1] != 0)) 107 | { 108 | 109 | byte serialconfig = 0x10; 110 | serialconfig += ExtraTaskSettings.TaskDevicePluginConfigLong[3]; 111 | serialconfig += (ExtraTaskSettings.TaskDevicePluginConfigLong[2] - 5) << 2; 112 | if (ExtraTaskSettings.TaskDevicePluginConfigLong[4] == 2) 113 | serialconfig += 0x20; 114 | Serial.begin(ExtraTaskSettings.TaskDevicePluginConfigLong[1], serialconfig); 115 | ser2netServer = new WiFiServer(ExtraTaskSettings.TaskDevicePluginConfigLong[0]); 116 | ser2netServer->begin(); 117 | 118 | if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 119 | { 120 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 121 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); 122 | delay(500); 123 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); 124 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 125 | } 126 | 127 | Plugin_020_init = true; 128 | } 129 | success = true; 130 | break; 131 | } 132 | 133 | case PLUGIN_TEN_PER_SECOND: 134 | { 135 | if (Plugin_020_init) 136 | { 137 | size_t bytes_read; 138 | if (!ser2netClient) 139 | { 140 | while (Serial.available()) { 141 | Serial.read(); 142 | } 143 | ser2netClient = ser2netServer->available(); 144 | } 145 | 146 | if (ser2netClient.connected()) 147 | { 148 | uint8_t net_buf[BUFFER_SIZE]; 149 | int count = ser2netClient.available(); 150 | if (count > 0) { 151 | if (count > BUFFER_SIZE) 152 | count = BUFFER_SIZE; 153 | bytes_read = ser2netClient.read(net_buf, count); 154 | Serial.write(net_buf, bytes_read); 155 | Serial.flush(); 156 | 157 | net_buf[count]=0; 158 | addLog(LOG_LEVEL_DEBUG,(char*)net_buf); 159 | 160 | } 161 | } 162 | success = true; 163 | } 164 | break; 165 | } 166 | 167 | case PLUGIN_SERIAL_IN: 168 | { 169 | if (Plugin_020_init) 170 | { 171 | if (ser2netClient.connected()) 172 | { 173 | uint8_t serial_buf[BUFFER_SIZE]; 174 | size_t bytes_read = 0; 175 | while (Serial.available() && bytes_read < BUFFER_SIZE) { 176 | serial_buf[bytes_read] = Serial.read(); 177 | bytes_read++; 178 | } 179 | if (bytes_read > 0) { 180 | ser2netClient.write((const uint8_t*)serial_buf, bytes_read); 181 | ser2netClient.flush(); 182 | } 183 | 184 | serial_buf[bytes_read]=0; 185 | addLog(LOG_LEVEL_DEBUG,(char*)serial_buf); 186 | 187 | } 188 | success = true; 189 | } 190 | break; 191 | } 192 | 193 | } 194 | return success; 195 | } 196 | 197 | -------------------------------------------------------------------------------- /_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 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_021); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_021)); 41 | break; 42 | } 43 | 44 | case PLUGIN_WEBFORM_LOAD: 45 | { 46 | char tmpString[128]; 47 | 48 | string += F("Check Task:"); 49 | addTaskSelect(string, "plugin_021_task", Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 50 | 51 | LoadTaskSettings(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 52 | string += F("Check Value:"); 53 | addTaskValueSelect(string, "plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 54 | 55 | // bug with %f in sprintf, this is a workaround: 56 | //sprintf(tmpString, "Set Value:", Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0]); 57 | //string += tmpString; 58 | //sprintf(tmpString, "Hysteresis:", Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1]); 59 | //string += tmpString; 60 | string += F("Set Value:"); 63 | string += F("Hysteresis:"); 66 | 67 | LoadTaskSettings(event->TaskIndex); 68 | success = true; 69 | break; 70 | } 71 | 72 | case PLUGIN_WEBFORM_SAVE: 73 | { 74 | String plugin1 = WebServer.arg("plugin_021_task"); 75 | String plugin2 = WebServer.arg("plugin_021_value"); 76 | String plugin3 = WebServer.arg("plugin_021_setvalue"); 77 | String plugin4 = WebServer.arg("plugin_021_hyst"); 78 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 79 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 80 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = plugin3.toFloat(); 81 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = plugin4.toFloat(); 82 | success = true; 83 | break; 84 | } 85 | 86 | case PLUGIN_INIT: 87 | { 88 | Serial.print(F("INIT : Output ")); 89 | Serial.println(Settings.TaskDevicePin1[event->TaskIndex]); 90 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 91 | success = true; 92 | break; 93 | } 94 | 95 | case PLUGIN_TEN_PER_SECOND: 96 | { 97 | // we're checking a var from another task, so calculate that basevar 98 | byte TaskIndex = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 99 | byte BaseVarIndex = TaskIndex * VARS_PER_TASK + Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 100 | float value = UserVar[BaseVarIndex]; 101 | byte state = switchstate[event->TaskIndex]; 102 | // compare with threshold value 103 | float valueLowThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] - (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 104 | float valueHighThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] + (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 105 | if (value <= valueLowThreshold) 106 | state = 1; 107 | if (value >= valueHighThreshold) 108 | state = 0; 109 | if (state != switchstate[event->TaskIndex]) 110 | { 111 | Serial.print(F("Out : State ")); 112 | Serial.println(state); 113 | switchstate[event->TaskIndex] = state; 114 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex],state); 115 | UserVar[event->BaseVarIndex] = state; 116 | sendData(event); 117 | } 118 | 119 | success = true; 120 | break; 121 | } 122 | 123 | } 124 | return success; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /_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 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICENAME: 39 | { 40 | string = F(PLUGIN_NAME_022); 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICEVALUENAMES: 45 | { 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_022)); 47 | break; 48 | } 49 | 50 | case PLUGIN_WRITE: 51 | { 52 | if (!Plugin_022_init) 53 | { 54 | // default mode is open drain ouput, drive leds connected to VCC 55 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)0x01); // reset the device 56 | delay(1); 57 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)B10100000); // set up for auto increment 58 | Plugin_022_writeRegister(PCA9685_MODE2, (byte)0x10); // set to output 59 | Plugin_022_init = true; 60 | } 61 | String tmpString = string; 62 | int argIndex = tmpString.indexOf(','); 63 | if (argIndex) 64 | tmpString = tmpString.substring(0, argIndex); 65 | if (tmpString.equalsIgnoreCase("PCAPWM")) 66 | { 67 | success = true; 68 | Plugin_022_Write(event->Par1, event->Par2); 69 | if (printToWeb) 70 | { 71 | printWebString += F("PCAPWM "); 72 | printWebString += event->Par1; 73 | printWebString += F(" Set to "); 74 | printWebString += event->Par2; 75 | printWebString += F("
"); 76 | } 77 | } 78 | break; 79 | } 80 | } 81 | return success; 82 | } 83 | 84 | 85 | //******************************************************************************** 86 | // PCA9685 config 87 | //******************************************************************************** 88 | void Plugin_022_writeRegister(int regAddress, byte data) { 89 | Wire.beginTransmission(PCA9685_ADDRESS); 90 | Wire.write(regAddress); 91 | Wire.write(data); 92 | Wire.endTransmission(); 93 | } 94 | 95 | 96 | //******************************************************************************** 97 | // PCA9685 write 98 | //******************************************************************************** 99 | boolean Plugin_022_Write(byte Par1, int Par2) 100 | { 101 | boolean success = false; 102 | uint16_t LED_ON = 0; 103 | uint16_t LED_OFF = Par2; 104 | Wire.beginTransmission(PCA9685_ADDRESS); 105 | Wire.write(0x06 + 4 * Par1); 106 | Wire.write(lowByte(LED_ON)); 107 | Wire.write(highByte(LED_ON)); 108 | Wire.write(lowByte(LED_OFF)); 109 | Wire.write(highByte(LED_OFF)); 110 | Wire.endTransmission(); 111 | } 112 | 113 | -------------------------------------------------------------------------------- /_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 | break; 53 | } 54 | 55 | case PLUGIN_GET_DEVICENAME: 56 | { 57 | string = F(PLUGIN_NAME_024); 58 | break; 59 | } 60 | 61 | case PLUGIN_GET_DEVICEVALUENAMES: 62 | { 63 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_024)); 64 | break; 65 | } 66 | 67 | case PLUGIN_WEBFORM_LOAD: 68 | { 69 | #define MLX90614_OPTION 2 70 | 71 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 72 | String options[MLX90614_OPTION]; 73 | uint optionValues[MLX90614_OPTION]; 74 | optionValues[0] = (0x07); 75 | options[0] = F("IR object temperature"); 76 | optionValues[1] = (0x06); 77 | options[1] = F("Ambient temperature"); 78 | string += F("Option:"); 91 | 92 | success = true; 93 | break; 94 | } 95 | 96 | case PLUGIN_WEBFORM_SAVE: 97 | { 98 | String plugin1 = WebServer.arg("plugin_024_option"); 99 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 100 | Plugin_024_init = false; // Force device setup next time 101 | success = true; 102 | break; 103 | } 104 | 105 | case PLUGIN_INIT: 106 | { 107 | Plugin_024_init = true; 108 | // if (!msgTemp024) // Mysensors 109 | // msgTemp024 = new MyMessage(event->BaseVarIndex, V_TEMP); //Mysensors 110 | // present(event->BaseVarIndex, S_TEMP); //Mysensors 111 | // Serial.print("Present MLX90614: "); //Mysensors 112 | // Serial.println(event->BaseVarIndex); //Mysensors 113 | success = true; 114 | break; 115 | } 116 | 117 | case PLUGIN_READ: 118 | { 119 | // noInterrupts(); 120 | int value; 121 | value = 0; 122 | byte unit = Settings.TaskDevicePort[event->TaskIndex]; 123 | uint8_t address = 0x5A + unit; 124 | UserVar[event->BaseVarIndex] = (float) readTemp024(address, Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 125 | String log = F("MLX90614 : Temperature: "); 126 | log += UserVar[event->BaseVarIndex]; 127 | // send(msgObjTemp024->set(UserVar[event->BaseVarIndex], 1)); // Mysensors 128 | addLog(LOG_LEVEL_INFO,log); 129 | success = true; 130 | // interrupts(); 131 | break; 132 | } 133 | } 134 | return success; 135 | } 136 | -------------------------------------------------------------------------------- /_P025_ADS1115.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 025: ADS1115 I2C 0x48) ############################################### 3 | //####################################################################################################### 4 | 5 | // MyMessage *msgAnalog025; // Mysensors 6 | 7 | #define PLUGIN_025 8 | #define PLUGIN_ID_025 25 9 | #define PLUGIN_NAME_025 "Analog input - ADS1115" 10 | #define PLUGIN_VALUENAME1_025 "Analog" 11 | 12 | boolean Plugin_025_init = false; 13 | // byte Plugin_Switch_Pin = 0; 14 | 15 | static uint16_t readRegister025(uint8_t i2cAddress, uint8_t reg) { 16 | Wire.beginTransmission(i2cAddress); 17 | Wire.write((0x00)); 18 | Wire.endTransmission(); 19 | Wire.requestFrom(i2cAddress, (uint8_t)2); 20 | return ((Wire.read() << 8) | Wire.read()); 21 | } 22 | 23 | boolean Plugin_025(byte function, struct EventStruct *event, String& string) 24 | { 25 | boolean success = false; 26 | static byte portValue = 0; 27 | switch (function) 28 | { 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_025; 32 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 33 | // Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 34 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 35 | Device[deviceCount].Ports = 4; 36 | Device[deviceCount].PullUpOption = false; 37 | Device[deviceCount].InverseLogicOption = false; 38 | Device[deviceCount].FormulaOption = true; 39 | Device[deviceCount].ValueCount = 1; 40 | Device[deviceCount].SendDataOption = true; 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICENAME: 45 | { 46 | string = F(PLUGIN_NAME_025); 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICEVALUENAMES: 51 | { 52 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_025)); 53 | break; 54 | } 55 | 56 | case PLUGIN_WEBFORM_LOAD: 57 | { 58 | #define ADS1115_GAIN_OPTION 6 59 | 60 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 61 | String options[ADS1115_GAIN_OPTION]; 62 | uint optionValues[ADS1115_GAIN_OPTION]; 63 | optionValues[0] = (0x00); 64 | options[0] = F("2/3x gain 6.144V 0.1875mV"); 65 | optionValues[1] = (0x02); 66 | options[1] = F("1x gain 4.096V 0.125mV"); 67 | optionValues[2] = (0x04); 68 | options[2] = F("2x gain 2.048V 0.0625mV"); 69 | optionValues[3] = (0x06); 70 | options[3] = F("4x gain 1.024V 0.03125mV"); 71 | optionValues[4] = (0x08); 72 | options[4] = F("8x gain 0.512V 0.015625mV"); 73 | optionValues[5] = (0x0A); 74 | options[5] = F("16x gain 0.256V 0.0078125V"); 75 | 76 | string += F("Gain:"); 89 | 90 | success = true; 91 | break; 92 | } 93 | 94 | case PLUGIN_WEBFORM_SAVE: 95 | { 96 | String plugin1 = WebServer.arg("plugin_025_gain"); 97 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 98 | Plugin_025_init = false; // Force device setup next time 99 | success = true; 100 | break; 101 | } 102 | 103 | case PLUGIN_INIT: 104 | { 105 | Plugin_025_init = true; 106 | // Plugin_Switch_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 107 | // if (!msgAnalog025) //Mysensors 108 | // msgDust025 = new MyMessage(event->BaseVarIndex, V_LEVEL); //Mysensors 109 | // present(event->BaseVarIndex, S_DUST); //Mysensors 110 | // Serial.print("Present ADS1115: "); // Mysensors 111 | // Serial.println(event->BaseVarIndex); // Mysensors 112 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 113 | // { 114 | // pinMode(Plugin_Switch_Pin, OUTPUT); 115 | // digitalWrite(Plugin_Switch_Pin, HIGH); 116 | // } 117 | success = true; 118 | break; 119 | } 120 | 121 | case PLUGIN_READ: 122 | { 123 | uint8_t m_gain = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 124 | // noInterrupts(); 125 | int value; 126 | value = 0; 127 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 128 | // { 129 | // Plugin_Switch_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 130 | // digitalWrite(Plugin_Switch_Pin, LOW); 131 | // delayMicroseconds(280); 132 | // } 133 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 134 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 135 | uint8_t address = 0x48 + unit; 136 | // get the current pin value 137 | 138 | uint16_t config = (0x0003) | // Disable the comparator (default val) 139 | (0x0000) | // Non-latching (default val) 140 | (0x0000) | // Alert/Rdy active low (default val) 141 | (0x0000) | // Traditional comparator (default val) 142 | (0x0080) | // 1600 samples per second (default) 143 | (0x0100) ; // Single-shot mode (default) 144 | 145 | // m_Gain = (0x0000); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) 146 | // m_Gain = (0x0200); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV 147 | // m_Gain = (0x0400); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV 148 | // m_Gain = (0x0600); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV 149 | // m_Gain = (0x0800); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV 150 | // m_Gain = (0x0A00); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV 151 | // config |= m_gain; 152 | // config |= (0x0000); 153 | switch (m_gain) 154 | { 155 | case (0x00): 156 | config |= (0x0000); 157 | break; 158 | case (0x02): 159 | config |= (0x0200); 160 | break; 161 | case (0x04): 162 | config |= (0x0400); 163 | break; 164 | case (0x06): 165 | config |= (0x0600); 166 | break; 167 | case (0x08): 168 | config |= (0x0800); 169 | break; 170 | case (0x0A): 171 | config |= (0x0A00); 172 | break; 173 | } 174 | switch (port) 175 | { 176 | case (0): 177 | config |= (0x4000); 178 | break; 179 | case (1): 180 | config |= (0x5000); 181 | break; 182 | case (2): 183 | config |= (0x6000); 184 | break; 185 | case (3): 186 | config |= (0x7000); 187 | break; 188 | } 189 | config |= (0x8000); 190 | Wire.beginTransmission(address); 191 | Wire.write((uint8_t)(0x01)); 192 | Wire.write((uint8_t)(config>>8)); 193 | Wire.write((uint8_t)(config & 0xFF)); 194 | Wire.endTransmission(); 195 | delay(8); 196 | UserVar[event->BaseVarIndex] = (float) readRegister025((address), (0x00)) ; 197 | String log = F("ADS1115 : Analog value: "); 198 | log += UserVar[event->BaseVarIndex]; 199 | // send(msgDust025->set(UserVar[event->BaseVarIndex], 1)); // Mysensors 200 | addLog(LOG_LEVEL_INFO,log); 201 | success = true; 202 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 203 | // { 204 | // delayMicroseconds(40); 205 | // digitalWrite(Plugin_Switch_Pin, HIGH); 206 | // } 207 | // interrupts(); 208 | break; 209 | } 210 | } 211 | return success; 212 | } 213 | -------------------------------------------------------------------------------- /_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 | break; 24 | } 25 | 26 | case PLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(PLUGIN_NAME_026); 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICEVALUENAMES: 33 | { 34 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_026)); 35 | break; 36 | } 37 | 38 | case PLUGIN_WEBFORM_LOAD: 39 | { 40 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 41 | String options[2]; 42 | options[0] = F("Uptime"); 43 | options[1] = F("Free RAM"); 44 | int optionValues[2]; 45 | optionValues[0] = 0; 46 | optionValues[1] = 1; 47 | string += F("Indicator:"); 60 | 61 | success = true; 62 | break; 63 | } 64 | 65 | case PLUGIN_WEBFORM_SAVE: 66 | { 67 | String plugin1 = WebServer.arg("plugin_026"); 68 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_READ: 74 | { 75 | float value = 0; 76 | switch(Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 77 | { 78 | case 0: 79 | { 80 | value = (wdcounter /2); 81 | break; 82 | } 83 | case 1: 84 | { 85 | value = ESP.getFreeHeap(); 86 | break; 87 | } 88 | } 89 | UserVar[event->BaseVarIndex] = value; 90 | String log = F("SYS : "); 91 | log += value; 92 | addLog(LOG_LEVEL_INFO,log); 93 | success = true; 94 | break; 95 | } 96 | } 97 | return success; 98 | } 99 | -------------------------------------------------------------------------------- /_P028_BME280.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 028 BME280 I2C Temp/Hum/Barometric Pressure Sensor ####################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_028 6 | #define PLUGIN_ID_028 28 7 | #define PLUGIN_NAME_028 "Temperature & Humidity & Pressure - BME280" 8 | #define PLUGIN_VALUENAME1_028 "Temperature" 9 | #define PLUGIN_VALUENAME2_028 "Humidity" 10 | #define PLUGIN_VALUENAME3_028 "Pressure" 11 | 12 | enum 13 | { 14 | BME280_REGISTER_DIG_T1 = 0x88, 15 | BME280_REGISTER_DIG_T2 = 0x8A, 16 | BME280_REGISTER_DIG_T3 = 0x8C, 17 | 18 | BME280_REGISTER_DIG_P1 = 0x8E, 19 | BME280_REGISTER_DIG_P2 = 0x90, 20 | BME280_REGISTER_DIG_P3 = 0x92, 21 | BME280_REGISTER_DIG_P4 = 0x94, 22 | BME280_REGISTER_DIG_P5 = 0x96, 23 | BME280_REGISTER_DIG_P6 = 0x98, 24 | BME280_REGISTER_DIG_P7 = 0x9A, 25 | BME280_REGISTER_DIG_P8 = 0x9C, 26 | BME280_REGISTER_DIG_P9 = 0x9E, 27 | 28 | BME280_REGISTER_DIG_H1 = 0xA1, 29 | BME280_REGISTER_DIG_H2 = 0xE1, 30 | BME280_REGISTER_DIG_H3 = 0xE3, 31 | BME280_REGISTER_DIG_H4 = 0xE4, 32 | BME280_REGISTER_DIG_H5 = 0xE5, 33 | BME280_REGISTER_DIG_H6 = 0xE7, 34 | 35 | BME280_REGISTER_CHIPID = 0xD0, 36 | BME280_REGISTER_VERSION = 0xD1, 37 | BME280_REGISTER_SOFTRESET = 0xE0, 38 | 39 | BME280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0 40 | 41 | BME280_REGISTER_CONTROLHUMID = 0xF2, 42 | BME280_REGISTER_CONTROL = 0xF4, 43 | BME280_REGISTER_CONFIG = 0xF5, 44 | BME280_REGISTER_PRESSUREDATA = 0xF7, 45 | BME280_REGISTER_TEMPDATA = 0xFA, 46 | BME280_REGISTER_HUMIDDATA = 0xFD, 47 | }; 48 | 49 | typedef struct 50 | { 51 | uint16_t dig_T1; 52 | int16_t dig_T2; 53 | int16_t dig_T3; 54 | 55 | uint16_t dig_P1; 56 | int16_t dig_P2; 57 | int16_t dig_P3; 58 | int16_t dig_P4; 59 | int16_t dig_P5; 60 | int16_t dig_P6; 61 | int16_t dig_P7; 62 | int16_t dig_P8; 63 | int16_t dig_P9; 64 | 65 | uint8_t dig_H1; 66 | int16_t dig_H2; 67 | uint8_t dig_H3; 68 | int16_t dig_H4; 69 | int16_t dig_H5; 70 | int8_t dig_H6; 71 | } bme280_calib_data; 72 | 73 | bme280_calib_data _bme280_calib; 74 | 75 | uint8_t _i2caddr; 76 | int32_t _sensorID; 77 | int32_t t_fine; 78 | 79 | boolean Plugin_028_init = false; 80 | 81 | boolean Plugin_028(byte function, struct EventStruct *event, String& string) 82 | { 83 | boolean success = false; 84 | 85 | switch (function) 86 | { 87 | case PLUGIN_DEVICE_ADD: 88 | { 89 | Device[++deviceCount].Number = PLUGIN_ID_028; 90 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 91 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM_BARO; 92 | Device[deviceCount].Ports = 0; 93 | Device[deviceCount].PullUpOption = false; 94 | Device[deviceCount].InverseLogicOption = false; 95 | Device[deviceCount].FormulaOption = true; 96 | Device[deviceCount].ValueCount = 3; 97 | Device[deviceCount].SendDataOption = true; 98 | break; 99 | } 100 | 101 | case PLUGIN_GET_DEVICENAME: 102 | { 103 | string = F(PLUGIN_NAME_028); 104 | break; 105 | } 106 | 107 | case PLUGIN_GET_DEVICEVALUENAMES: 108 | { 109 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_028)); 110 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_028)); 111 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_028)); 112 | break; 113 | } 114 | 115 | case PLUGIN_READ: 116 | { 117 | if (!Plugin_028_init) 118 | { 119 | Plugin_028_init = true; 120 | Plugin_028_begin(0x76); 121 | } 122 | UserVar[event->BaseVarIndex] = Plugin_028_readTemperature(); 123 | UserVar[event->BaseVarIndex + 1] = ((float)Plugin_028_readHumidity()); 124 | UserVar[event->BaseVarIndex + 2] = ((float)Plugin_028_readPressure()) / 100; 125 | String log = F("BME : Temperature: "); 126 | log += UserVar[event->BaseVarIndex]; 127 | addLog(LOG_LEVEL_INFO, log); 128 | log = F("BME : Humidity: "); 129 | log += UserVar[event->BaseVarIndex + 1]; 130 | addLog(LOG_LEVEL_INFO, log); 131 | log = F("BME : Barometric Pressure: "); 132 | log += UserVar[event->BaseVarIndex + 2]; 133 | addLog(LOG_LEVEL_INFO, log); 134 | success = true; 135 | break; 136 | } 137 | 138 | } 139 | return success; 140 | } 141 | 142 | //**************************************************************************/ 143 | // Initialize BME280 144 | //**************************************************************************/ 145 | bool Plugin_028_begin(uint8_t a) { 146 | _i2caddr = a; 147 | 148 | if (Plugin_028_read8(BME280_REGISTER_CHIPID) != 0x60) 149 | return false; 150 | 151 | Plugin_028_readCoefficients(); 152 | Plugin_028_write8(BME280_REGISTER_CONTROLHUMID, 0x03); 153 | Plugin_028_write8(BME280_REGISTER_CONTROL, 0x3F); 154 | return true; 155 | } 156 | 157 | //**************************************************************************/ 158 | // Writes an 8 bit value over I2C/SPI 159 | //**************************************************************************/ 160 | void Plugin_028_write8(byte reg, byte value) 161 | { 162 | Wire.beginTransmission((uint8_t)_i2caddr); 163 | Wire.write((uint8_t)reg); 164 | Wire.write((uint8_t)value); 165 | Wire.endTransmission(); 166 | } 167 | 168 | //**************************************************************************/ 169 | // Reads an 8 bit value over I2C 170 | //**************************************************************************/ 171 | uint8_t Plugin_028_read8(byte reg) 172 | { 173 | uint8_t value; 174 | 175 | Wire.beginTransmission((uint8_t)_i2caddr); 176 | Wire.write((uint8_t)reg); 177 | Wire.endTransmission(); 178 | Wire.requestFrom((uint8_t)_i2caddr, (byte)1); 179 | value = Wire.read(); 180 | Wire.endTransmission(); 181 | return value; 182 | } 183 | 184 | //**************************************************************************/ 185 | // Reads a 16 bit value over I2C 186 | //**************************************************************************/ 187 | uint16_t Plugin_028_read16(byte reg) 188 | { 189 | uint16_t value; 190 | 191 | Wire.beginTransmission((uint8_t)_i2caddr); 192 | Wire.write((uint8_t)reg); 193 | Wire.endTransmission(); 194 | Wire.requestFrom((uint8_t)_i2caddr, (byte)2); 195 | value = (Wire.read() << 8) | Wire.read(); 196 | Wire.endTransmission(); 197 | 198 | return value; 199 | } 200 | 201 | //**************************************************************************/ 202 | // Reads a 16 bit value over I2C 203 | //**************************************************************************/ 204 | uint16_t Plugin_028_read16_LE(byte reg) { 205 | uint16_t temp = Plugin_028_read16(reg); 206 | return (temp >> 8) | (temp << 8); 207 | 208 | } 209 | 210 | //**************************************************************************/ 211 | // Reads a signed 16 bit value over I2C 212 | //**************************************************************************/ 213 | int16_t Plugin_028_readS16(byte reg) 214 | { 215 | return (int16_t)Plugin_028_read16(reg); 216 | 217 | } 218 | 219 | int16_t Plugin_028_readS16_LE(byte reg) 220 | { 221 | return (int16_t)Plugin_028_read16_LE(reg); 222 | 223 | } 224 | 225 | //**************************************************************************/ 226 | // Reads the factory-set coefficients 227 | //**************************************************************************/ 228 | void Plugin_028_readCoefficients(void) 229 | { 230 | _bme280_calib.dig_T1 = Plugin_028_read16_LE(BME280_REGISTER_DIG_T1); 231 | _bme280_calib.dig_T2 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_T2); 232 | _bme280_calib.dig_T3 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_T3); 233 | 234 | _bme280_calib.dig_P1 = Plugin_028_read16_LE(BME280_REGISTER_DIG_P1); 235 | _bme280_calib.dig_P2 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P2); 236 | _bme280_calib.dig_P3 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P3); 237 | _bme280_calib.dig_P4 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P4); 238 | _bme280_calib.dig_P5 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P5); 239 | _bme280_calib.dig_P6 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P6); 240 | _bme280_calib.dig_P7 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P7); 241 | _bme280_calib.dig_P8 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P8); 242 | _bme280_calib.dig_P9 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_P9); 243 | 244 | _bme280_calib.dig_H1 = Plugin_028_read8(BME280_REGISTER_DIG_H1); 245 | _bme280_calib.dig_H2 = Plugin_028_readS16_LE(BME280_REGISTER_DIG_H2); 246 | _bme280_calib.dig_H3 = Plugin_028_read8(BME280_REGISTER_DIG_H3); 247 | _bme280_calib.dig_H4 = (Plugin_028_read8(BME280_REGISTER_DIG_H4) << 4) | (Plugin_028_read8(BME280_REGISTER_DIG_H4 + 1) & 0xF); 248 | _bme280_calib.dig_H5 = (Plugin_028_read8(BME280_REGISTER_DIG_H5 + 1) << 4) | (Plugin_028_read8(BME280_REGISTER_DIG_H5) >> 4); 249 | _bme280_calib.dig_H6 = (int8_t)Plugin_028_read8(BME280_REGISTER_DIG_H6); 250 | } 251 | 252 | //**************************************************************************/ 253 | // Read temperature 254 | //**************************************************************************/ 255 | float Plugin_028_readTemperature(void) 256 | { 257 | int32_t var1, var2; 258 | 259 | int32_t adc_T = Plugin_028_read16(BME280_REGISTER_TEMPDATA); 260 | adc_T <<= 8; 261 | adc_T |= Plugin_028_read8(BME280_REGISTER_TEMPDATA + 2); 262 | adc_T >>= 4; 263 | 264 | var1 = ((((adc_T >> 3) - ((int32_t)_bme280_calib.dig_T1 << 1))) * 265 | ((int32_t)_bme280_calib.dig_T2)) >> 11; 266 | 267 | var2 = (((((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1)) * 268 | ((adc_T >> 4) - ((int32_t)_bme280_calib.dig_T1))) >> 12) * 269 | ((int32_t)_bme280_calib.dig_T3)) >> 14; 270 | 271 | t_fine = var1 + var2; 272 | 273 | float T = (t_fine * 5 + 128) >> 8; 274 | return T / 100; 275 | } 276 | 277 | //**************************************************************************/ 278 | // Read pressure 279 | //**************************************************************************/ 280 | float Plugin_028_readPressure(void) { 281 | int64_t var1, var2, p; 282 | 283 | int32_t adc_P = Plugin_028_read16(BME280_REGISTER_PRESSUREDATA); 284 | adc_P <<= 8; 285 | adc_P |= Plugin_028_read8(BME280_REGISTER_PRESSUREDATA + 2); 286 | adc_P >>= 4; 287 | 288 | var1 = ((int64_t)t_fine) - 128000; 289 | var2 = var1 * var1 * (int64_t)_bme280_calib.dig_P6; 290 | var2 = var2 + ((var1 * (int64_t)_bme280_calib.dig_P5) << 17); 291 | var2 = var2 + (((int64_t)_bme280_calib.dig_P4) << 35); 292 | var1 = ((var1 * var1 * (int64_t)_bme280_calib.dig_P3) >> 8) + 293 | ((var1 * (int64_t)_bme280_calib.dig_P2) << 12); 294 | var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)_bme280_calib.dig_P1) >> 33; 295 | 296 | if (var1 == 0) { 297 | return 0; // avoid exception caused by division by zero 298 | } 299 | p = 1048576 - adc_P; 300 | p = (((p << 31) - var2) * 3125) / var1; 301 | var1 = (((int64_t)_bme280_calib.dig_P9) * (p >> 13) * (p >> 13)) >> 25; 302 | var2 = (((int64_t)_bme280_calib.dig_P8) * p) >> 19; 303 | 304 | p = ((p + var1 + var2) >> 8) + (((int64_t)_bme280_calib.dig_P7) << 4); 305 | return (float)p / 256; 306 | } 307 | 308 | //**************************************************************************/ 309 | // Read humidity 310 | //**************************************************************************/ 311 | float Plugin_028_readHumidity(void) { 312 | 313 | int32_t adc_H = Plugin_028_read16(BME280_REGISTER_HUMIDDATA); 314 | 315 | int32_t v_x1_u32r; 316 | 317 | v_x1_u32r = (t_fine - ((int32_t)76800)); 318 | 319 | v_x1_u32r = (((((adc_H << 14) - (((int32_t)_bme280_calib.dig_H4) << 20) - 320 | (((int32_t)_bme280_calib.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) * 321 | (((((((v_x1_u32r * ((int32_t)_bme280_calib.dig_H6)) >> 10) * 322 | (((v_x1_u32r * ((int32_t)_bme280_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + 323 | ((int32_t)2097152)) * ((int32_t)_bme280_calib.dig_H2) + 8192) >> 14)); 324 | 325 | v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * 326 | ((int32_t)_bme280_calib.dig_H1)) >> 4)); 327 | 328 | v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; 329 | v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; 330 | float h = (v_x1_u32r >> 12); 331 | return h / 1024.0; 332 | } 333 | 334 | //**************************************************************************/ 335 | // Calculates the altitude (in meters) from the specified atmospheric 336 | // pressure (in hPa), and sea-level pressure (in hPa). 337 | // @param seaLevel Sea-level pressure in hPa 338 | // @param atmospheric Atmospheric pressure in hPa 339 | //**************************************************************************/ 340 | float Plugin_028_readAltitude(float seaLevel) 341 | { 342 | // Equation taken from BMP180 datasheet (page 16): 343 | // http://www.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf 344 | 345 | // Note that using the equation from wikipedia can give bad results 346 | // at high altitude. See this thread for more information: 347 | // http://forums.adafruit.com/viewtopic.php?f=22&t=58064 348 | 349 | float atmospheric = Plugin_028_readPressure() / 100.0F; 350 | return 44330.0 * (1.0 - pow(atmospheric / seaLevel, 0.1903)); 351 | } 352 | 353 | -------------------------------------------------------------------------------- /__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); 136 | return true; 137 | break; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | --------------------------------------------------------------------------------