├── Dialog_Plain_18_font.h ├── Extra_Utilities.ino ├── P178_Frogmore_SCD30_Arduino_Library ├── FrogmoreScd30.cpp └── FrogmoreScd30.h ├── README.md ├── _C004.ino ├── _C022.ino ├── _C025.ino ├── _P096_Vito.ino ├── _P100_SRF01.ino ├── _P101_NeoClock.ino ├── _P102_Nodo.ino ├── _P103_Event.ino ├── _P104_SRF02.ino ├── _P105_RGBW.ino ├── _P106_IRTX.ino ├── _P107_Email_Demo.ino ├── _P108_WOL.ino ├── _P109_RESOL_DeltaSol_Pro.ino ├── _P110_P1WifiGateway.ino ├── _P111_RF.ino ├── _P111_SenseAir.ino ├── _P112_Power.ino ├── _P112_RFTX.ino ├── _P113_SI1145.ino ├── _P114_DSM501.ino ├── _P115_HeatpumpIR.ino ├── _P116_ID12.ino ├── _P117_LW12FC.ino ├── _P117_Neopixels ├── _P117_Nextion.ino ├── _P118_CCS811.ino ├── _P119_BME680.ino ├── _P120_Thermocouple.ino ├── _P121_Candle.ino ├── _P122_NeoPixel.ino ├── _P123_SI7013.ino ├── _P124_NeoPixelBusFX.ino ├── _P124_Ventus_W266_RFM69.ino ├── _P125_ArduCAM.ino ├── _P126_HassDiscovery.ino ├── _P126_Ping.ino ├── _P127_Teleinfo.ino ├── _P128_AS3935.ino ├── _P128_HassSwitch.ino ├── _P129_RC522_RFID.ino ├── _P130_VEML6075.ino ├── _P131_SHT3X.ino ├── _P133_VL53L0X.ino ├── _P134_PPD42.ino ├── _P135_MQ135.ino ├── _P141_LedStrip.ino ├── _P142_RGB-Strip.ino ├── _P143_AnyonePresent.ino ├── _P144_RC-Switch-TX.ino ├── _P145_Itho.ino ├── _P149_MHZ19.ino ├── _P150_SDM120C.ino ├── _P151_CISA.ino ├── _P152_MCP42010.ino ├── _P153_MAX44009.ino ├── _P156_DS1307.ino ├── _P157_DS3231.ino ├── _P158_Yeti.ino ├── _P159_Pushbutton.ino ├── _P160_OutputMulti.ino ├── _P161_Switchboard.ino ├── _P162_MPL3115A2.ino ├── _P163_DS1631.ino ├── _P165_SerSwitch.ino ├── _P166_WiFiMan.ino ├── _P167_ADS1015.ino ├── _P168_ThermOLED.ino ├── _P169_FO_WH24_RFM69.ino ├── _P170_HLW8012.ino ├── _P171_PZEM-004T.ino ├── _P176_CDM7160.ino ├── _P178_SCD30.ino ├── _P180_Mux.ino ├── _P181_TempHumidity_SHT2x.ino ├── _P182_MT681.ino ├── _P183_SMA.ino ├── _P184_GY_US42V2.ino ├── _P197_RFLink_MQTT_Bridge.ino ├── _P198_Venta.ino ├── _P199_RF443_KaKu.ino ├── _P202_ADC_ACcurrentSensor.ino ├── _P203_Feeder.ino ├── _P205_FrameOLED.ino ├── _P209_IFTTTMaker.ino ├── _P210_MQTTImport.ino ├── _P211_MPU6050.ino ├── _P212_MY9291.ino ├── _P213_VEML6070 ├── _P214_Atlas_EZO_pH.ino ├── _P215_Atlas_EZO_EC.ino ├── _P216_LIFX.ino ├── _P216_PMS5003ST.ino ├── _P216_PMSx003ST.ino ├── _P217_ACS712AC.ino ├── _P218_BlindControl.ino ├── _P218_MaxbotixEZ_Distance.ino ├── _P218_SlowPWM.ino ├── _P221_LandisGyrUH550.ino ├── _P222_Atlas_EZO_ORP.ino ├── _P242_ILI9341.ino ├── _P243_Schedule.ino ├── _P245_Hoben.ino ├── esp8266-oled-ssd1306.zip └── libraries _PLUGIN145 ITHO FAN └── Itho ├── CC1101.cpp ├── CC1101.h ├── CC1101Packet.h ├── IthoCC1101.cpp ├── IthoCC1101.h └── IthoPacket.h /P178_Frogmore_SCD30_Arduino_Library/FrogmoreScd30.h: -------------------------------------------------------------------------------- 1 | /* 2 | # Copyright (c) 2019 Frogmore42 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | */ 21 | #pragma once 22 | 23 | #include "Arduino.h" 24 | 25 | //#define SCD30_DEBUG 26 | 27 | #define SCD30_ADDRESS 0x61 28 | #define ERROR_SCD30_NO_ERROR 0 29 | #define ERROR_SCD30_NO_DATA 0x80000000 30 | #define ERROR_SCD30_CO2_ZERO 0x90000000 31 | #define ERROR_SCD30_UNKNOWN_ERROR 0x1000000 32 | #define ERROR_SCD30_CRC_ERROR 0x2000000 33 | #define ERROR_SCD30_NOT_ENOUGH_BYTES_ERROR 0x3000000 34 | #define ERROR_SCD30_NOT_FOUND_ERROR 0x4000000 35 | #define ERROR_SCD30_NOT_A_NUMBER_ERROR 0x5000000 36 | #define ERROR_SCD30_INVALID_VALUE 0x6000000 37 | 38 | #define SCD30_MEDIAN_FILTER_SIZE 5 39 | 40 | class FrogmoreScd30 41 | { 42 | public: 43 | FrogmoreScd30() {}; 44 | // Constructors 45 | // the SCD30 only lists a single i2c address, so not necesary to specify 46 | // 47 | void begin(void); 48 | void begin(uint8_t _i2cAddress); 49 | void begin(TwoWire *pWire); 50 | void begin(TwoWire *pWire, uint8_t _i2cAddress); 51 | 52 | int softReset(void); 53 | int clearI2CBus(void); // this is a HARD reset of the IC2 bus to restore communication, it will disrupt the bus 54 | 55 | int getAltitudeCompensation(uint16_t *pHeight_meter); 56 | int getAmbientPressure(uint16_t *pAirPressure_mbar); 57 | int getCalibrationType(uint16_t *pIsAuto); 58 | int getFirmwareVersion(uint8_t *pMajor, uint8_t *pMinor); 59 | int getForcedRecalibrationFactor(uint16_t *pCo2_ppm); 60 | int getMeasurementInterval(uint16_t *pTime_sec); 61 | int getTemperatureOffset(float *pOffset_degC); 62 | int getTemperatureOffset(uint16_t *pOffset_centiDegC); 63 | 64 | int setAltitudeCompensation(uint16_t height_meter); 65 | int setAmbientPressure(uint16_t airPressure_mbar); 66 | int setAutoSelfCalibration(void); 67 | int setCalibrationType(bool isAuto); 68 | int setForcedRecalibrationFactor(uint16_t co2_ppm); 69 | int setManualCalibration(void); 70 | int setMeasurementInterval(uint16_t time_sec); 71 | int setTemperatureOffset(float offset_degC); 72 | int setTemperatureOffset(uint16_t offset_centiDegC); 73 | 74 | int beginMeasuring(void); 75 | int beginMeasuring(uint16_t airPressure_mbar); // also sets ambient pressure offset in mbar/hPascal 76 | int isDataAvailable(bool *pIsAvailable); 77 | int readMeasurement( 78 | uint16 *pCO2_ppm, 79 | uint16 *pCO2EAvg_ppm, 80 | float *pTemperature, 81 | float *pHumidity 82 | ); 83 | int stopMeasuring(void); 84 | 85 | private: 86 | uint8_t i2cAddress; 87 | TwoWire *pWire; 88 | uint16_t ambientPressure; 89 | uint16_t co2AvgExtra; 90 | uint16_t co2History[SCD30_MEDIAN_FILTER_SIZE]; 91 | uint16_t co2EAverage; 92 | int8_t co2NewDataLocation; // location to put new CO2 data for median filter 93 | 94 | uint8_t computeCRC8(uint8_t data[], uint8_t len); 95 | int sendBytes(void *pInput, uint8_t len); 96 | int getBytes(void *pOutput, uint8_t len); 97 | int sendCommand(uint16_t command); 98 | int sendCommandArguments(uint16_t command, uint16_t arguments); 99 | int get16BitRegCheckCRC(void* pInput, uint16_t* pData); 100 | int get32BitRegCheckCRC(void* pInput, float* pData); 101 | int readRegister(uint16_t registerAddress, uint16_t* pData); 102 | #ifdef SCD30_DEBUG 103 | void AddLog(uint8_t loglevel); 104 | #endif 105 | }; 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPEasyPluginPlayground 2 | Plugin ideas, concepts, user contributed, etc 3 | 4 | Plugin ID's should be unique and numbered between 100 - 199. Filenames should use the \_Pxxx\_ prefix. 5 | 6 | Remember: Playground plugins can be in any state from development to stable and they are published without verification by the development team. 7 | 8 | The main ESPEasy repo and plugins are here: https://github.com/letscontrolit/ESPEasy 9 | 10 | ## Getting the plugin into the main repository 11 | 12 | Look here for the guidelines on getting the plugin in the main-repository, and make it a standard part of ESPEasy: https://www.letscontrolit.com/wiki/index.php/ESPEasyDevelopmentGuidelines 13 | -------------------------------------------------------------------------------- /_C004.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 104: ThingSpeak ######################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_004 6 | #define CPLUGIN_ID_004 4 7 | #define CPLUGIN_NAME_004 "ThingSpeak" 8 | 9 | #define NUM_OF_FIELDS 8 10 | #define THINGSPEAK_DELAY 15 11 | 12 | float field_data[NUM_OF_FIELDS]; 13 | byte field_format[NUM_OF_FIELDS]; 14 | unsigned long thingspeak_timer; 15 | 16 | boolean CPlugin_004(byte function, struct EventStruct *event, String& string) 17 | { 18 | boolean success = false; 19 | byte x; 20 | 21 | switch (function) 22 | { 23 | case CPLUGIN_PROTOCOL_ADD: 24 | { 25 | Protocol[++protocolCount].Number = CPLUGIN_ID_004; 26 | Protocol[protocolCount].usesMQTT = false; 27 | Protocol[protocolCount].usesAccount = false; 28 | Protocol[protocolCount].usesPassword = true; 29 | Protocol[protocolCount].defaultPort = 80; 30 | 31 | thingspeak_timer = millis() + THINGSPEAK_DELAY*1000 + 30000; 32 | for(byte i=0; isensorType); 52 | for (x = 0; x < valueCount; x++) 53 | { 54 | if(event->idx + x - 1 < NUM_OF_FIELDS) 55 | { 56 | field_data[event->idx + x - 1] = UserVar[event->BaseVarIndex + x]; 57 | field_format[event->idx + x - 1] = ExtraTaskSettings.TaskDeviceValueDecimals[x]; 58 | } 59 | } 60 | 61 | 62 | if(millis() > thingspeak_timer) 63 | { 64 | String postDataStr = F("api_key="); 65 | postDataStr += SecuritySettings.ControllerPassword; // used for API key 66 | boolean sendUpdate = false; 67 | for (x = 0; x < NUM_OF_FIELDS; x++) 68 | { 69 | if(field_format[x]!=255) 70 | { 71 | postDataStr += F("&field"); 72 | postDataStr += x+1; 73 | postDataStr += "="; 74 | int tmp = (int)(field_data[x]*100); 75 | postDataStr += toString(field_data[x],field_format[x]); 76 | sendUpdate = true; 77 | } 78 | } 79 | 80 | if(sendUpdate) 81 | { 82 | thingspeak_timer = millis() + THINGSPEAK_DELAY*1000; 83 | 84 | char host[20]; 85 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 86 | 87 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 88 | addLog(LOG_LEVEL_DEBUG, log); 89 | 90 | WiFiClient client; 91 | if (!client.connect(host, Settings.ControllerPort)) 92 | { 93 | connectionFailures++; 94 | strcpy_P(log, PSTR("HTTP : connection failed")); 95 | addLog(LOG_LEVEL_ERROR, log); 96 | thingspeak_timer -= Settings.Delay*1000; 97 | return false; 98 | } 99 | statusLED(true); 100 | if (connectionFailures) 101 | connectionFailures--; 102 | 103 | String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers. 104 | if (Settings.UseDNS) 105 | hostName = Settings.ControllerHostName; 106 | 107 | String postStr = F("POST /update HTTP/1.1\r\n"); 108 | postStr += F("Host: "); 109 | postStr += hostName; 110 | postStr += F("\r\n"); 111 | postStr += F("Connection: close\r\n"); 112 | 113 | postStr += F("Content-Type: application/x-www-form-urlencoded\r\n"); 114 | postStr += F("Content-Length: "); 115 | postStr += postDataStr.length(); 116 | postStr += F("\r\n\r\n"); 117 | postStr += postDataStr; 118 | 119 | // This will send the request to the server 120 | client.print(postStr); 121 | 122 | unsigned long timer = millis() + 200; 123 | while (!client.available() && millis() < timer) 124 | delay(1); 125 | 126 | // Read all the lines of the reply from server and print them to Serial 127 | while (client.available()) { 128 | String line = client.readStringUntil('\n'); 129 | line.toCharArray(log, 80); 130 | addLog(LOG_LEVEL_DEBUG_MORE, log); 131 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 132 | { 133 | strcpy_P(log, PSTR("HTTP : Succes!")); 134 | addLog(LOG_LEVEL_DEBUG, log); 135 | success = true; 136 | } 137 | delay(1); 138 | } 139 | strcpy_P(log, PSTR("HTTP : closing connection")); 140 | addLog(LOG_LEVEL_DEBUG, log); 141 | 142 | client.flush(); 143 | client.stop(); 144 | 145 | for(byte i=0; i210" core statement to comply (and function) with new standard 230 core as of R114, 24 September 2016 13 | * 14 | /******************************************************************************/ 15 | 16 | #define CPLUGIN_022 17 | #define CPLUGIN_ID_022 22 18 | #define CPLUGIN_NAME_022 "Pimatic RestApi" 19 | 20 | boolean CPlugin_022(byte function, struct EventStruct *event, String& string) 21 | { 22 | boolean success = false; 23 | 24 | switch (function) 25 | { 26 | case CPLUGIN_PROTOCOL_ADD: 27 | { 28 | Protocol[++protocolCount].Number = CPLUGIN_ID_022; 29 | Protocol[protocolCount].usesMQTT = false; 30 | Protocol[protocolCount].usesAccount = true; 31 | Protocol[protocolCount].usesPassword = true; 32 | Protocol[protocolCount].defaultPort = 80; 33 | break; 34 | } 35 | 36 | case CPLUGIN_GET_DEVICENAME: 37 | { 38 | string = F(CPLUGIN_NAME_022); 39 | break; 40 | } 41 | 42 | case CPLUGIN_PROTOCOL_SEND: 43 | { 44 | switch (event->sensorType) 45 | { 46 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 47 | case SENSOR_TYPE_SWITCH: 48 | case SENSOR_TYPE_DIMMER: 49 | pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0); 50 | break; 51 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 52 | pimaticUpdateVariable(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 53 | break; 54 | case SENSOR_TYPE_TEMP_HUM: 55 | case SENSOR_TYPE_TEMP_BARO: 56 | { 57 | pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0); 58 | unsigned long timer = millis() + Settings.MessageDelay; 59 | while (millis() < timer) 60 | backgroundtasks(); 61 | pimaticUpdateVariable(event, 1, UserVar[event->BaseVarIndex + 1], 0); 62 | break; 63 | } 64 | case SENSOR_TYPE_TEMP_HUM_BARO: 65 | { 66 | pimaticUpdateVariable(event, 0, UserVar[event->BaseVarIndex], 0); 67 | unsigned long timer = millis() + Settings.MessageDelay; 68 | while (millis() < timer) 69 | backgroundtasks(); 70 | pimaticUpdateVariable(event, 1, UserVar[event->BaseVarIndex + 1], 0); 71 | timer = millis() + Settings.MessageDelay; 72 | while (millis() < timer) 73 | backgroundtasks(); 74 | pimaticUpdateVariable(event, 2, UserVar[event->BaseVarIndex + 2], 0); 75 | break; 76 | } 77 | } 78 | break; 79 | } 80 | 81 | } 82 | return success; 83 | } 84 | 85 | 86 | //******************************************************************************** 87 | // Pimatic updateVariable 88 | //******************************************************************************** 89 | boolean pimaticUpdateVariable(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 90 | { 91 | 92 | String authHeader = ""; 93 | 94 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 95 | { 96 | base64 encoder; 97 | String auth = SecuritySettings.ControllerUser; 98 | auth += ":"; 99 | auth += SecuritySettings.ControllerPassword; 100 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 101 | } 102 | 103 | 104 | char log[80]; 105 | boolean success = false; 106 | char host[20]; 107 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 108 | 109 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 110 | addLog(LOG_LEVEL_DEBUG, log); 111 | 112 | // Use WiFiClient class to create TCP connections 113 | WiFiClient client; 114 | if (!client.connect(host, Settings.ControllerPort)) 115 | { 116 | connectionFailures++; 117 | strcpy_P(log, PSTR("HTTP : connection failed")); 118 | addLog(LOG_LEVEL_ERROR, log); 119 | return false; 120 | } 121 | statusLED(true); 122 | if (connectionFailures) 123 | connectionFailures--; 124 | 125 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 126 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 127 | 128 | String url = "/api/variables/"; 129 | url += URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex]); 130 | url.toCharArray(log, 80); 131 | addLog(LOG_LEVEL_DEBUG_MORE, log); 132 | 133 | String data; 134 | if (longValue) 135 | data = String(longValue); 136 | else 137 | data = toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex]); 138 | 139 | String yourdata = "{\"type\": \"value\", \"valueOrExpression\": \"" + data + "\"}"; 140 | 141 | String hostName = host; 142 | if (Settings.UseDNS) 143 | hostName = Settings.ControllerHostName; 144 | 145 | // This will send the request to the server 146 | client.print(String("PATCH ") + url + " HTTP/1.1\r\n" + 147 | authHeader + 148 | "Host: " + hostName + "\r\n" + 149 | "Content-Type:application/json\r\n" + 150 | "Content-Length: " + yourdata.length() + "\r\n\r\n" + 151 | yourdata); 152 | 153 | unsigned long timer = millis() + 200; 154 | while (!client.available() && millis() < timer) 155 | delay(1); 156 | 157 | // Read all the lines of the reply from server and print them to Serial 158 | while (client.available()) { 159 | String line = client.readStringUntil('\n'); 160 | line.toCharArray(log, 80); 161 | addLog(LOG_LEVEL_DEBUG_MORE, log); 162 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 163 | { 164 | strcpy_P(log, PSTR("HTTP : Succes!")); 165 | addLog(LOG_LEVEL_DEBUG, log); 166 | success = true; 167 | } 168 | delay(1); 169 | } 170 | strcpy_P(log, PSTR("HTTP : closing connection")); 171 | addLog(LOG_LEVEL_DEBUG, log); 172 | 173 | client.flush(); 174 | client.stop(); 175 | } 176 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /_P100_SRF01.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 100 SRF01 Ultrasonic Distance Sensor ###################################### 3 | //####################################################################################################### 4 | 5 | #include 6 | 7 | #define PLUGIN_100 8 | #define PLUGIN_ID_100 100 9 | #define PLUGIN_NAME_100 "Ultrasonic Sensor - SRF01" 10 | #define PLUGIN_VALUENAME1_100 "Distance" 11 | 12 | #define PLUGIN_100_srfAddress 0x01 // Address of the SFR01, default ist 0x01 13 | #define PLUGIN_100_getSoft 0x5D // Byte to tell SRF01 we wish to read software version 14 | #define PLUGIN_100_getRange 0x54 // Byte used to get range from SRF01 in cm 15 | #define PLUGIN_100_getStatus 0x5F // Byte used to get the status of the transducer 16 | 17 | SoftwareSerial *Plugin_100_SRF; 18 | 19 | uint8_t Plugin_100_SRF_Pin; 20 | 21 | boolean Plugin_100(byte function, struct EventStruct *event, String& string) 22 | { 23 | boolean success = false; 24 | byte timeout; 25 | 26 | switch (function) 27 | { 28 | case PLUGIN_DEVICE_ADD: 29 | { 30 | Device[++deviceCount].Number = PLUGIN_ID_100; 31 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 32 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 33 | Device[deviceCount].Ports = 0; 34 | Device[deviceCount].PullUpOption = false; 35 | Device[deviceCount].InverseLogicOption = false; 36 | Device[deviceCount].FormulaOption = true; 37 | Device[deviceCount].ValueCount = 1; 38 | Device[deviceCount].SendDataOption = true; 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICENAME: 43 | { 44 | string = F(PLUGIN_NAME_100); 45 | break; 46 | } 47 | 48 | case PLUGIN_GET_DEVICEVALUENAMES: 49 | { 50 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_100)); 51 | break; 52 | } 53 | 54 | 55 | case PLUGIN_INIT: 56 | { 57 | addLog(LOG_LEVEL_INFO, (char*)"INIT : SRF01"); 58 | Plugin_100_SRF_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 59 | Plugin_100_SRF = new SoftwareSerial(Plugin_100_SRF_Pin, Plugin_100_SRF_Pin); 60 | Plugin_100_SRF01_Cmd(PLUGIN_100_srfAddress, PLUGIN_100_getSoft); 61 | for (timeout = 0; timeout < 10; timeout++) { 62 | if (Plugin_100_SRF->available() < 1 ) { 63 | delay(10); 64 | } else { 65 | int softVer = Plugin_100_SRF->read(); 66 | String log = F("SRF01 : Firmware-Version: "); 67 | log += softVer; 68 | addLog(LOG_LEVEL_INFO, log); 69 | success = true; 70 | return success; 71 | }; 72 | }; 73 | addLog(LOG_LEVEL_ERROR, (char*)"SRF01-Init: protocol timeout!"); 74 | success = false; 75 | break; 76 | } 77 | 78 | case PLUGIN_READ: 79 | { 80 | Plugin_100_SRF01_Cmd(PLUGIN_100_srfAddress, PLUGIN_100_getRange); 81 | for (timeout = 0; timeout < 10; timeout++) { 82 | if (Plugin_100_SRF->available() < 2 ) { 83 | delay(10); 84 | } else { 85 | byte highByte = Plugin_100_SRF->read(); 86 | byte lowByte = Plugin_100_SRF->read(); 87 | int dist = ((highByte << 8) + lowByte); 88 | UserVar[event->BaseVarIndex] = dist; 89 | String log = F("SRF1 : Distance: "); 90 | log += dist; 91 | addLog(LOG_LEVEL_INFO, log); 92 | success = true; 93 | return success; 94 | }; 95 | }; 96 | addLog(LOG_LEVEL_ERROR, (char*)"SRF01 : protocol timeout!"); 97 | UserVar[event->BaseVarIndex] = NAN; 98 | success = false; 99 | break; 100 | } 101 | 102 | } 103 | return success; 104 | } 105 | 106 | //**************************************************************************/ 107 | // Send SRF01 Command 108 | //**************************************************************************/ 109 | void Plugin_100_SRF01_Cmd(byte Address, byte cmd) { 110 | Plugin_100_SRF->flush(); 111 | pinMode(Plugin_100_SRF_Pin, OUTPUT); 112 | digitalWrite(Plugin_100_SRF_Pin, LOW); 113 | delay(2); 114 | digitalWrite(Plugin_100_SRF_Pin, HIGH); 115 | delay(1); 116 | Plugin_100_SRF->write(Address); 117 | Plugin_100_SRF->write(cmd); 118 | pinMode(Plugin_100_SRF_Pin, INPUT); 119 | Plugin_100_SRF->flush(); 120 | } 121 | 122 | -------------------------------------------------------------------------------- /_P102_Nodo.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 102: Nodo Event Bridge V2 ################################# 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_102 6 | #define PLUGIN_ID_102 102 7 | #define PLUGIN_NAME_102 "Nodo Event Bridge V2" 8 | #define PLUGIN_VALUENAME1_102 "" 9 | 10 | boolean Plugin_102(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte unicastTargetUnit = 0; 14 | 15 | switch (function) 16 | { 17 | 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_102; 21 | Device[deviceCount].Custom = true; 22 | break; 23 | } 24 | 25 | case PLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(PLUGIN_NAME_102); 28 | break; 29 | } 30 | 31 | case PLUGIN_GET_DEVICEVALUENAMES: 32 | { 33 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_102)); 34 | break; 35 | } 36 | 37 | case PLUGIN_UDP_IN: 38 | { 39 | // event->Data is pointer to UDP buffer 40 | if (event->Data[0] == 255 && event->Data[1] == 254) 41 | { 42 | if (event->Data[11] == 0) // normal traffic, Nodo flags are 0 43 | { 44 | unicastTargetUnit = 0; 45 | } 46 | else 47 | { 48 | unicastTargetUnit = event->Data[9]; // remote source Nodo unit will be unicast target 49 | } 50 | for (byte x = 0; x < 16; x++) 51 | Serial.write(event->Data[x]); 52 | } 53 | success = true; 54 | break; 55 | } 56 | 57 | case PLUGIN_SERIAL_IN: 58 | { 59 | if (Serial.peek() == 255) 60 | { 61 | delay(20); // wait for message to complete 62 | if (Serial.read() == 255 && Serial.read() == 254) 63 | { 64 | byte data[16]; 65 | data[0] = 255; 66 | data[1] = 254; 67 | byte count = 2; 68 | while (Serial.available() && count < 16) 69 | data[count++] = Serial.read(); 70 | 71 | IPAddress sendIP(255, 255, 255, 255); 72 | 73 | if (data[11] != 0) // flags set, set to unicast mode 74 | { 75 | if ((unicastTargetUnit != 0) && (Nodes[unicastTargetUnit].ip[0] != 0)) 76 | for(byte x=0; x <4; x++) 77 | sendIP[x] = Nodes[unicastTargetUnit].ip[x]; 78 | } 79 | 80 | portUDP.beginPacket(sendIP, Settings.UDPPort); 81 | portUDP.write(data, 16); 82 | portUDP.endPacket(); 83 | } 84 | success = true; 85 | } 86 | break; 87 | } 88 | 89 | } 90 | return success; 91 | } 92 | 93 | -------------------------------------------------------------------------------- /_P104_SRF02.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################### Plugin 104: SRF02 Ultrasonic range finder sensor ############################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_104 6 | #define PLUGIN_ID_104 104 7 | #define PLUGIN_NAME_104 "Ultrasonic range finder - SRF02" 8 | #define PLUGIN_VALUENAME1_104 "DISTANCE" 9 | 10 | #define SRF02_ADDRESS (0x70) // default address (0x70 = datasheet address 0xE0) 11 | 12 | #define SRF02_REG_COMMAND (0x00) // a read on this register returns the software revision 13 | #define SRF02_REG_UNUSED (0x01) 14 | #define SRF02_REG_RANGE_HIGH_BYTE (0x02) 15 | #define SRF02_REG_RANGE_LOW_BYTE (0x03) 16 | #define SRF02_REG_AUTOTUNE_MINIMUM_HIGH_BYTE (0x04) 17 | #define SRF02_REG_AUTOTUNE_MINIMUM_LOW_BYTE (0x05) 18 | 19 | #define SRF02_CMD_REAL_RANGING_MODE_INCH (0x50) 20 | #define SRF02_CMD_REAL_RANGING_MODE_CM (0x51) 21 | #define SRF02_CMD_REAL_RANGING_MODE_US (0x52) 22 | 23 | #define SRF02_CMD_FAKE_RANGING_MODE_INCH (0x56) 24 | #define SRF02_CMD_FAKE_RANGING_MODE_CM (0x57) 25 | #define SRF02_CMD_FAKE_RANGING_MODE_US (0x58) 26 | 27 | #define SRF02_CMD_FORCE_AUTOTUNE_RESTART (0x5C) 28 | 29 | #define SRF02_CMD_I2C_CHANGE_SEQ_1 (0xA0) 30 | #define SRF02_CMD_I2C_CHANGE_SEQ_2 (0xA5) 31 | #define SRF02_CMD_I2C_CHANGE_SEQ_3 (0xAA) 32 | 33 | 34 | uint8_t SRF02_i2caddr; 35 | 36 | boolean Plugin_104(byte function, struct EventStruct *event, String& string) 37 | { 38 | boolean success = false; 39 | 40 | switch (function) 41 | { 42 | 43 | case PLUGIN_DEVICE_ADD: 44 | { 45 | Device[++deviceCount].Number = PLUGIN_ID_104; 46 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 47 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 48 | Device[deviceCount].Ports = 0; 49 | Device[deviceCount].PullUpOption = false; 50 | Device[deviceCount].InverseLogicOption = false; 51 | Device[deviceCount].FormulaOption = true; 52 | Device[deviceCount].TimerOption = true; 53 | Device[deviceCount].TimerOptional = true; 54 | Device[deviceCount].ValueCount = 1; 55 | Device[deviceCount].SendDataOption = true; 56 | break; 57 | } 58 | 59 | case PLUGIN_GET_DEVICENAME: 60 | { 61 | string = F(PLUGIN_NAME_104); 62 | break; 63 | } 64 | 65 | case PLUGIN_GET_DEVICEVALUENAMES: 66 | { 67 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_104)); 68 | break; 69 | } 70 | 71 | case PLUGIN_WEBFORM_LOAD: 72 | { 73 | success = true; 74 | break; 75 | } 76 | 77 | case PLUGIN_WEBFORM_SAVE: 78 | { 79 | success = true; 80 | break; 81 | } 82 | 83 | case PLUGIN_INIT: 84 | { 85 | Plugin_104_begin(); 86 | success = true; 87 | break; 88 | } 89 | 90 | case PLUGIN_READ: 91 | { 92 | float value; 93 | value = Plugin_104_getDistance(); 94 | UserVar[event->BaseVarIndex] = value; 95 | String log = F("P104 : distance = "); 96 | log += value; 97 | log += F(" mm"); 98 | addLog(LOG_LEVEL_INFO,log); 99 | success = true; 100 | break; 101 | } 102 | } 103 | return success; 104 | } 105 | 106 | //**************************************************************************/ 107 | // I2C single byte write 108 | //**************************************************************************/ 109 | void Plugin_104_wireWriteByte(uint8_t reg, uint8_t value) 110 | { 111 | Wire.beginTransmission(SRF02_i2caddr); 112 | Wire.write(reg); 113 | Wire.write(value); 114 | Wire.endTransmission(); 115 | } 116 | 117 | //**************************************************************************/ 118 | // I2C two byte read 119 | //**************************************************************************/ 120 | void Plugin_104_wireReadTwoBytes(uint8_t reg, uint16_t *value) 121 | { 122 | Wire.beginTransmission(SRF02_i2caddr); 123 | Wire.write(reg); 124 | Wire.endTransmission(); 125 | 126 | delayMicroseconds(10); 127 | 128 | Wire.requestFrom(SRF02_i2caddr, (uint8_t)2); 129 | *value = ((Wire.read() << 8) | Wire.read()); 130 | } 131 | 132 | //**************************************************************************/ 133 | // Sensor setup 134 | //**************************************************************************/ 135 | void Plugin_104_begin(void) 136 | { 137 | SRF02_i2caddr = SRF02_ADDRESS; 138 | } 139 | 140 | //**************************************************************************/ 141 | // Report distance 142 | //**************************************************************************/ 143 | float Plugin_104_getDistance() 144 | { 145 | uint16_t value; 146 | 147 | Plugin_104_wireWriteByte(SRF02_REG_COMMAND, SRF02_CMD_REAL_RANGING_MODE_US); 148 | delay(70); // transmit -> receive turnaround time (up to 65ms) 149 | Plugin_104_wireReadTwoBytes(SRF02_REG_RANGE_HIGH_BYTE, &value); 150 | 151 | return (float)value/(float)5.82750583; // distance in [mm] (2*1000/343.2) 152 | } 153 | -------------------------------------------------------------------------------- /_P106_IRTX.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 106: Output IR ############################################ 3 | //####################################################################################################### 4 | 5 | // Moved to ESPEasy as P035 (R124) 6 | -------------------------------------------------------------------------------- /_P107_Email_Demo.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 107: Email (Demo) ######################################### 3 | //####################################################################################################### 4 | 5 | // This is just a demo plugin. It does send an email after pressing the "Submit" button, but that's all it can do! 6 | // Needs to be expanded in some way to be useful. 7 | 8 | #define PLUGIN_107 9 | #define PLUGIN_ID_107 107 10 | #define PLUGIN_NAME_107 "Notify - Email" 11 | #define PLUGIN_VALUENAME1_107 "email" 12 | 13 | #define PLUGIN_107_TIMEOUT 3000 14 | 15 | struct P107Struct 16 | { 17 | char server[64]; 18 | byte port; 19 | char domain[64]; 20 | char to[64]; 21 | char from[64]; 22 | char subject[64]; 23 | char body[64]; 24 | }; 25 | 26 | boolean Plugin_107(byte function, struct EventStruct *event, String& string) 27 | { 28 | boolean success = false; 29 | 30 | switch (function) 31 | { 32 | 33 | case PLUGIN_DEVICE_ADD: 34 | { 35 | Device[++deviceCount].Number = PLUGIN_ID_107; 36 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 37 | Device[deviceCount].Custom = true; 38 | Device[deviceCount].TimerOption = false; 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICENAME: 43 | { 44 | string = F(PLUGIN_NAME_107); 45 | break; 46 | } 47 | 48 | case PLUGIN_GET_DEVICEVALUENAMES: 49 | { 50 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_107)); 51 | break; 52 | } 53 | 54 | case PLUGIN_WEBFORM_LOAD: 55 | { 56 | struct P107Struct email; 57 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&email, sizeof(email)); 58 | string += F("Server:"); 61 | string += F("Server port:"); 64 | string += F("Domain:"); 67 | string += F("Mail To:"); 70 | string += F("Mail From:"); 73 | string += F("Subject:"); 76 | string += F("Body:"); 79 | success = true; 80 | break; 81 | } 82 | 83 | case PLUGIN_WEBFORM_SAVE: 84 | { 85 | struct P107Struct email; 86 | String plugin1 = WebServer.arg("Plugin_107_server"); 87 | strncpy(email.server, plugin1.c_str(), sizeof(email.server)); 88 | String plugin2 = WebServer.arg("Plugin_107_port"); 89 | email.port = plugin2.toInt(); 90 | String plugin3 = WebServer.arg("Plugin_107_domain"); 91 | strncpy(email.domain, plugin3.c_str(), sizeof(email.domain)); 92 | String plugin4 = WebServer.arg("Plugin_107_to"); 93 | strncpy(email.to, plugin4.c_str(), sizeof(email.to)); 94 | String plugin5 = WebServer.arg("Plugin_107_from"); 95 | strncpy(email.from, plugin5.c_str(), sizeof(email.from)); 96 | String plugin6 = WebServer.arg("Plugin_107_subject"); 97 | strncpy(email.subject, plugin6.c_str(), sizeof(email.subject)); 98 | String plugin7 = WebServer.arg("Plugin_107_subject"); 99 | strncpy(email.body, plugin7.c_str(), sizeof(email.body)); 100 | 101 | Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value 102 | 103 | SaveCustomTaskSettings(event->TaskIndex, (byte*)&email, sizeof(email)); 104 | success = true; 105 | break; 106 | } 107 | 108 | case PLUGIN_INIT: 109 | { 110 | struct P107Struct email; 111 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&email, sizeof(email)); 112 | Plugin_107_send(email.domain,email.to,email.from,email.subject,email.body,email.server,email.port); 113 | break; 114 | } 115 | 116 | case PLUGIN_WRITE: 117 | { 118 | String tmpString = string; 119 | int argIndex = tmpString.indexOf(','); 120 | if (argIndex) 121 | tmpString = tmpString.substring(0, argIndex); 122 | if (tmpString.equalsIgnoreCase("email")) 123 | { 124 | event->TaskIndex=event->Par1-1; 125 | struct P107Struct email; 126 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&email, sizeof(email)); 127 | Plugin_107_send(email.domain,email.to,email.from,email.subject,email.body,email.server,email.port); 128 | success = true; 129 | } 130 | break; 131 | } 132 | } 133 | return success; 134 | } 135 | 136 | 137 | boolean Plugin_107_send(String aDomain , String aTo, String aFrom, String aSub, String aMesg, String aHost, int aPort) 138 | { 139 | boolean myStatus = false; 140 | 141 | // Use WiFiClient class to create TCP connections 142 | WiFiClient client; 143 | if (!client.connect(aHost.c_str(), aPort)) { 144 | myStatus = false; 145 | } 146 | else { 147 | 148 | // Wait for Client to Start Sending 149 | // The MTA Exchange 150 | while (true) { 151 | 152 | if (Plugin_107_MTA(client, "", "220 ") == false) break; 153 | if (Plugin_107_MTA(client, "EHLO " + aDomain, "250 ") == false) break; 154 | if (Plugin_107_MTA(client, "MAIL FROM:" + aFrom + "", "250 ") == false) break; 155 | if (Plugin_107_MTA(client, "RCPT TO:" + aTo + "", "250 ") == false) break; 156 | if (Plugin_107_MTA(client, "DATA", "354 ") == false) break; 157 | if (Plugin_107_MTA(client, "Subject:" + aSub + "\r\n\r\n" + aMesg + "\r\n.\r\n", "250 ") == false) break; 158 | 159 | myStatus = true; 160 | break; 161 | 162 | } 163 | 164 | client.flush(); 165 | client.stop(); 166 | 167 | if (myStatus == true) { 168 | Serial.println(" Connection Closed Successfully"); 169 | } 170 | else { 171 | Serial.println(" Connection Closed With Error"); 172 | } 173 | 174 | } 175 | 176 | return myStatus; 177 | 178 | } 179 | 180 | 181 | boolean Plugin_107_MTA(WiFiClient client, String aStr, String aWaitForPattern) 182 | { 183 | 184 | boolean myStatus = false; 185 | 186 | if (aStr.length() ) client.println(aStr); 187 | 188 | yield(); 189 | 190 | // Wait For Response 191 | unsigned long ts = millis(); 192 | while (true) { 193 | if ( ts + PLUGIN_107_TIMEOUT < millis() ) { 194 | myStatus = false; 195 | break; 196 | } 197 | 198 | yield(); 199 | 200 | String line = client.readStringUntil('\n'); 201 | 202 | if (line.indexOf(aWaitForPattern) >= 0) { 203 | myStatus = true; 204 | break; 205 | } 206 | } 207 | 208 | return myStatus; 209 | } 210 | 211 | -------------------------------------------------------------------------------- /_P108_WOL.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 108: WOL receiver ######################################### 3 | //####################################################################################################### 4 | 5 | // This plugin receives Wake On Lan (WOL) messages that can be used to power on a connected device. 6 | // Note that the ESP itself has no WOL feature. It must be active to receive this message. 7 | // So you can't wake an ESP from deepsleep using WOL because Wifi is down during deepsleep. 8 | 9 | #define PLUGIN_108 10 | #define PLUGIN_ID_108 108 11 | #define PLUGIN_NAME_108 "WOL Receiver" 12 | #define PLUGIN_VALUENAME1_108 "WOL" 13 | 14 | WiFiUDP *WOL; 15 | 16 | boolean Plugin_108(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_108; 26 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 27 | Device[deviceCount].Custom = true; 28 | Device[deviceCount].TimerOption = false; 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_108); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_108)); 41 | break; 42 | } 43 | 44 | case PLUGIN_WEBFORM_LOAD: 45 | { 46 | string += F("Power control pin:"); 47 | addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]); 48 | 49 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 50 | String options[2]; 51 | options[0] = F("Active Low"); 52 | options[1] = F("Active High"); 53 | int optionValues[2]; 54 | optionValues[0] = 0; 55 | optionValues[1] = 1; 56 | string += F("Output state:"); 69 | 70 | success = true; 71 | break; 72 | } 73 | 74 | case PLUGIN_WEBFORM_SAVE: 75 | { 76 | String plugin1 = WebServer.arg("plugin_108_state"); 77 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_INIT: 83 | { 84 | if (!WOL) 85 | { 86 | WOL = new WiFiUDP; 87 | WOL->begin(7); 88 | } 89 | if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 90 | { 91 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 92 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], !Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 93 | } 94 | } 95 | success = true; 96 | break; 97 | 98 | case PLUGIN_ONCE_A_SECOND: 99 | { 100 | int packetSize = WOL->parsePacket(); 101 | if (packetSize) 102 | { 103 | statusLED(true); 104 | char packetBuffer[128]; 105 | int len = WOL->read(packetBuffer, 128); 106 | byte match = 0; 107 | uint8_t mac[] = {0, 0, 0, 0, 0, 0}; 108 | uint8_t* macread = WiFi.macAddress(mac); 109 | for (byte x = 0; x < 10; x++) 110 | if (packetBuffer[x + 6] == macread[x]) 111 | match++; 112 | if (match == 6) 113 | { 114 | String log = F("WOL : Magic packet received!"); 115 | addLog(LOG_LEVEL_INFO, log); 116 | if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 117 | { 118 | String log = F("WOL : Power cycle using pin: "); 119 | log += Settings.TaskDevicePin1[event->TaskIndex]; 120 | addLog(LOG_LEVEL_INFO, log); 121 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 122 | delay(500); 123 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], !Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 124 | } 125 | } 126 | } 127 | success = true; 128 | break; 129 | } 130 | } 131 | return success; 132 | } 133 | 134 | -------------------------------------------------------------------------------- /_P109_RESOL_DeltaSol_Pro.ino: -------------------------------------------------------------------------------- 1 | #ifdef PLUGIN_BUILD_TESTING 2 | 3 | //####################################################################################################### 4 | //################################## Plugin 109 RESOL DeltaSol Pro ###################################### 5 | //####################################################################################################### 6 | 7 | 8 | #include 9 | 10 | #define PLUGIN_109 11 | #define PLUGIN_ID_109 109 12 | #define PLUGIN_NAME_109 "RESOL DeltaSol Pro [TESTING]" 13 | #define PLUGIN_VALUENAME1_109 "register" 14 | 15 | // uart rx-buffer size 16 | #define RXBUF_SIZE 32 17 | 18 | // RESOL register options 19 | #define REG_TEMP_SENSOR_1 0 20 | #define REG_TEMP_SENSOR_2 1 21 | #define REG_TEMP_SENSOR_3 2 22 | #define REG_RELAIS_1 3 23 | #define REG_RELAIS_2 4 24 | 25 | // total number of selectable registers 26 | #define RESOL_REGISTER_OPTIONS 5 27 | 28 | uint8_t Plugin_109_UART_Pin; 29 | boolean Plugin_109_init = false; 30 | boolean valuesValid = false; 31 | uint8_t RXbuf[RXBUF_SIZE]; 32 | uint8_t RXbuf_IDX; 33 | int16_t T1, T2 ,T3; 34 | uint8_t R1, R2; 35 | 36 | ESPeasySoftwareSerial *Plugin_109_UART; 37 | 38 | 39 | // RESOL CRC check 40 | uint8_t VBus_CalcCrc(uint8_t *buf, uint8_t len) 41 | { 42 | uint8_t crc; 43 | 44 | crc = 0x7F; 45 | 46 | for (uint8_t i = 0; i < len; i++) 47 | crc = (crc - buf [i]) & 0x7F; 48 | 49 | return crc; 50 | } 51 | 52 | 53 | boolean Plugin_109(byte function, struct EventStruct *event, String& string) 54 | { 55 | boolean success = false; 56 | 57 | switch (function) 58 | { 59 | case PLUGIN_DEVICE_ADD: 60 | { 61 | Device[++deviceCount].Number = PLUGIN_ID_109; 62 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 63 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 64 | Device[deviceCount].Ports = 0; 65 | Device[deviceCount].PullUpOption = false; 66 | Device[deviceCount].InverseLogicOption = false; 67 | Device[deviceCount].FormulaOption = true; 68 | Device[deviceCount].ValueCount = 1; 69 | Device[deviceCount].SendDataOption = true; 70 | Device[deviceCount].TimerOption = true; 71 | Device[deviceCount].TimerOptional = true; 72 | Device[deviceCount].GlobalSyncOption = true; 73 | break; 74 | } 75 | 76 | case PLUGIN_GET_DEVICENAME: 77 | { 78 | string = F(PLUGIN_NAME_109); 79 | break; 80 | } 81 | 82 | case PLUGIN_GET_DEVICEVALUENAMES: 83 | { 84 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_109)); 85 | break; 86 | } 87 | 88 | case PLUGIN_WEBFORM_LOAD: 89 | { 90 | int16_t choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 91 | 92 | 93 | String registerOptions[5]; 94 | registerOptions[0] = F("Temperature sensor 1"); 95 | registerOptions[1] = F("Temperature sensor 2"); 96 | registerOptions[2] = F("Temperature sensor 3"); 97 | registerOptions[3] = F("Relais 1"); 98 | registerOptions[4] = F("Relais 2"); 99 | int registerOptionValues[5] = 100 | { REG_TEMP_SENSOR_1, REG_TEMP_SENSOR_2, REG_TEMP_SENSOR_3, REG_RELAIS_1, REG_RELAIS_2 }; 101 | addFormSelector(F("Register Type"), F("plugin_109_register"), 5, registerOptions, registerOptionValues, choice); 102 | 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_WEBFORM_SAVE: 108 | { 109 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_109_register")); 110 | Plugin_109_init = false; // Force device setup next time 111 | success = true; 112 | break; 113 | } 114 | 115 | case PLUGIN_INIT: 116 | { 117 | addLog(LOG_LEVEL_INFO, (char*)"INIT : RESOL DeltaSol Pro"); 118 | 119 | Plugin_109_UART = new ESPeasySoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], false, (2 * RXBUF_SIZE)); // set RX und Tx Pin number, no invert, buffer 120 | 121 | Plugin_109_init = true; 122 | 123 | success = true; 124 | break; 125 | } 126 | 127 | case PLUGIN_TEN_PER_SECOND: 128 | { 129 | if (Plugin_109_init == true) 130 | { 131 | // buffer filled with more than twize the frame size bytes? -> at least one complete frame should then be available 132 | if (Plugin_109_UART->available() > (2 * 30)) 133 | { 134 | // search for first appearance of SOF (0xAA) 135 | while ((Plugin_109_UART->available()) && (Plugin_109_UART->read() != 0xAA)); 136 | 137 | RXbuf_IDX = 0; 138 | RXbuf[RXbuf_IDX] = 0; 139 | 140 | while ((Plugin_109_UART->available()) && (RXbuf[RXbuf_IDX] != 0xAA) && (RXbuf_IDX < (RXBUF_SIZE - 1))) 141 | RXbuf[++RXbuf_IDX] = Plugin_109_UART->read(); 142 | 143 | if (RXbuf[RXbuf_IDX] == 0xAA) 144 | { 145 | // ********* DeltaSol Pro registers ********* 146 | 147 | // check CRC of first and second group 148 | if ( (VBus_CalcCrc(&RXbuf[10], 5) == RXbuf[15]) && (VBus_CalcCrc(&RXbuf[16], 5) == RXbuf[21]) ) 149 | { 150 | // Temperature sensor 1 151 | T1 = RXbuf[10] + ((RXbuf[14] & (1 << 0)) << 7); 152 | T1 += (RXbuf[11] + ((RXbuf[14] & (1 << 1)) << 6)) << 8; 153 | 154 | // Temperature sensor 2 155 | T2 = RXbuf[12] + ((RXbuf[14] & (1 << 2)) << 5); 156 | T2 += (RXbuf[13] + ((RXbuf[14] & (1 << 3)) << 4)) << 8; 157 | 158 | 159 | // Temperature sensor 3 160 | T3 = RXbuf[16] + ((RXbuf[20] & (1 << 0)) << 7); 161 | T3 += (RXbuf[17] + ((RXbuf[20] & (1 << 1)) << 6)) << 8; 162 | 163 | // Relais/speed 164 | R1 = RXbuf[18] + ((RXbuf[20] & (1 << 2)) << 5); 165 | R2 = RXbuf[19] + ((RXbuf[20] & (1 << 3)) << 4); 166 | 167 | valuesValid = true; 168 | } else 169 | valuesValid = false; 170 | } 171 | 172 | Plugin_109_UART->flush(); 173 | } 174 | } 175 | 176 | success = true; 177 | break; 178 | } 179 | 180 | case PLUGIN_READ: 181 | { 182 | float regValue; 183 | String log = F("RESOL : "); 184 | 185 | if (valuesValid == true) 186 | { 187 | switch (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 188 | { 189 | case REG_TEMP_SENSOR_1: 190 | { 191 | log += F("T1"); 192 | regValue = (float)T1 / 10; 193 | break; 194 | } 195 | 196 | case REG_TEMP_SENSOR_2: 197 | { 198 | log += F("T2"); 199 | regValue = (float)T2 / 10; 200 | break; 201 | } 202 | 203 | case REG_TEMP_SENSOR_3: 204 | { 205 | log += F("T3"); 206 | regValue = (float)T3 / 10; 207 | break; 208 | } 209 | 210 | case REG_RELAIS_1: 211 | { 212 | log += F("R1"); 213 | regValue = R1; 214 | break; 215 | } 216 | 217 | case REG_RELAIS_2: 218 | { 219 | log += F("R2"); 220 | regValue = R2; 221 | break; 222 | } 223 | default: 224 | { 225 | log += F("unknown"); 226 | regValue = 0; 227 | break; 228 | } 229 | } 230 | 231 | log += F("="); 232 | log += regValue; 233 | addLog(LOG_LEVEL_INFO, log); 234 | 235 | UserVar[event->BaseVarIndex] = regValue; 236 | success = true; 237 | break; 238 | } 239 | } 240 | } 241 | return success; 242 | } 243 | 244 | #endif 245 | -------------------------------------------------------------------------------- /_P114_DSM501.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 114: DMS501A ############################################# 3 | //#################################### by serpa ############################################# 4 | //####################################################################################################### 5 | 6 | #define PLUGIN_114 7 | #define PLUGIN_ID_114 114 8 | #define PLUGIN_NAME_114 "Dust sensor - DSM501a" 9 | #define PLUGIN_VALUENAME1_114 "PM1.0" // from the datasheet the detection is from PM1 and up. You could have from PM1 to PM2.5, on subtracting PM2.5 value on PM1 value. This value come from the pin #4 10 | #define PLUGIN_VALUENAME2_114 "PM2.5" // from the datasheet the detection is from PM2.5 and up. This value come from the pin #2. With different resistor topn the pin #1, you could adjust the size threshold detection 11 | 12 | unsigned long Plugin_114_pulseCounter[TASKS_MAX]; 13 | unsigned long Plugin_114_pulseTotalCounter[TASKS_MAX]; 14 | unsigned long Plugin_114_pulseTime[TASKS_MAX]; 15 | unsigned long Plugin_114_pulseTimePrevious[TASKS_MAX]; 16 | unsigned long tstart1, tstart2; 17 | unsigned long tduration = 30000; // duration of measurement in ms 18 | //unsigned long triggerOn; // start of pulse time in us 19 | //unsigned long triggerOff; // end of pulse time in us 20 | //unsigned long lowpulseoccupancy; // duration of pulse in us 21 | volatile unsigned long thigh1, thigh2; 22 | volatile unsigned long tlow1, tlow2; 23 | volatile unsigned long startlow1, startlow2; 24 | volatile unsigned long starthigh1, starthigh2; 25 | volatile boolean done1, done2; 26 | volatile boolean value1, value2; 27 | //boolean trigger = false; 28 | volatile float ratio1, ratio2; 29 | volatile int DMSpin1, DMSpin2; 30 | float dens1, dens2; 31 | boolean Plugin_114(byte function, struct EventStruct *event, String& string) 32 | { 33 | boolean success = false; 34 | 35 | switch (function) 36 | { 37 | 38 | case PLUGIN_DEVICE_ADD: 39 | { 40 | Device[++deviceCount].Number = PLUGIN_ID_114; 41 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 42 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 43 | Device[deviceCount].Ports = 0; 44 | Device[deviceCount].PullUpOption = false; 45 | Device[deviceCount].InverseLogicOption = false; 46 | Device[deviceCount].FormulaOption = true; 47 | Device[deviceCount].ValueCount = 2; 48 | Device[deviceCount].SendDataOption = true; 49 | Device[deviceCount].TimerOption = true; 50 | break; 51 | } 52 | 53 | case PLUGIN_GET_DEVICENAME: 54 | { 55 | string = F(PLUGIN_NAME_114); 56 | break; 57 | } 58 | 59 | case PLUGIN_GET_DEVICEVALUENAMES: 60 | { 61 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_114)); 62 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_114)); 63 | break; 64 | } 65 | 66 | case PLUGIN_WEBFORM_LOAD: 67 | { 68 | char tmpString[128]; 69 | sprintf_P(tmpString, PSTR("Averaging Time (mSec):"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 70 | addHtml(tmpString); 71 | success = true; 72 | break; 73 | } 74 | 75 | case PLUGIN_WEBFORM_SAVE: 76 | { 77 | String plugin1 = WebServer.arg("plugin_114"); 78 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 79 | // tduration= Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 80 | success = true; 81 | break; 82 | } 83 | 84 | 85 | case PLUGIN_INIT: 86 | { 87 | String log = F("INIT : DSM501A "); 88 | log += Settings.TaskDevicePin1[event->TaskIndex]; 89 | addLog(LOG_LEVEL_INFO, log); 90 | // tduration= Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 91 | tstart1 = millis(); 92 | startlow1 = micros(); 93 | starthigh1 = startlow1; 94 | DMSpin1 = Settings.TaskDevicePin1[event->TaskIndex]; 95 | pinMode(DMSpin1, INPUT); 96 | attachInterrupt(digitalPinToInterrupt(DMSpin1), Plugin_114_ISR1, CHANGE); 97 | tstart2 = millis(); 98 | startlow2 = micros(); 99 | starthigh2 = startlow2; 100 | DMSpin2 = Settings.TaskDevicePin2[event->TaskIndex]; 101 | pinMode(DMSpin2, INPUT); 102 | attachInterrupt(digitalPinToInterrupt(DMSpin2), Plugin_114_ISR2, CHANGE); 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_READ: 108 | { 109 | if (done1 && done2) { 110 | done1 = FALSE; 111 | dens1 = ratio1 * 110; // ug/m^3 112 | done2 = FALSE; 113 | dens2 = ratio2 * 110; // ug/m^3 114 | 115 | String log = F("DSM501A: PM1.0="); 116 | log += dens1; 117 | log += F(" PM2.5="); 118 | log += dens2; 119 | addLog(LOG_LEVEL_INFO, log); 120 | UserVar[event->BaseVarIndex] = (float) dens1; 121 | UserVar[event->BaseVarIndex + 1] = (float) dens2; 122 | } 123 | success = true; 124 | break; 125 | } 126 | } 127 | return success; 128 | } 129 | 130 | 131 | /*********************************************************************************************\ 132 | Check Pulse (called from irq handler) 133 | \*********************************************************************************************/ 134 | void Plugin_114_ISR1() 135 | { 136 | value1 = digitalRead(DMSpin1); //read input pin just changed 137 | if (value1 == 0) { // gone low 138 | startlow1 = micros(); // record starting of low period 139 | thigh1 += startlow1 - starthigh1; // record duration of past high state 140 | } else { // gone high 141 | starthigh1 = micros(); // record starting of high period 142 | tlow1 += starthigh1 - startlow1; // record duration of past low state 143 | } 144 | if (millis() > tstart1 + tduration) { // check if average time has past 145 | tstart1 = millis(); // reset time period 146 | ratio1 = float(tlow1) / float(thigh1 + tlow1) * 100; // compute ratio low to total 147 | tlow1 = 0; // reset low time counter 148 | thigh1 = 0; // reset high time counter 149 | done1 = TRUE; // set reading complete flag 150 | } 151 | } 152 | /*********************************************************************************************\ 153 | Check Pulse (called from irq handler) 154 | \*********************************************************************************************/ 155 | void Plugin_114_ISR2() 156 | { 157 | value2 = digitalRead(DMSpin2); //read input pin just changed 158 | if (value2 == 0) { // gone low 159 | startlow2 = micros(); // record starting of low period 160 | thigh2 += startlow2 - starthigh2; // record duration of past high state 161 | } else { // gone high 162 | starthigh2 = micros(); // record starting of high period 163 | tlow2 += starthigh2 - startlow2; // record duration of past low state 164 | } 165 | if (millis() > tstart2 + tduration) { // check if average time has past 166 | tstart2 = millis(); // reset time period 167 | ratio2 = float(tlow2) / float(thigh2 + tlow2) * 100; // compute ratio low to high 168 | tlow2 = 0; // reset low time counter 169 | thigh2 = 0; // reset high time counter 170 | done2 = TRUE; // set reading complete flag 171 | } 172 | } 173 | 174 | /////////////////////////////////////////////////////////////////////////////////////////////////////// 175 | -------------------------------------------------------------------------------- /_P115_HeatpumpIR.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 115: Heatpump IR ########################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_115 6 | #define PLUGIN_ID_115 115 7 | #define PLUGIN_NAME_115 "Heatpump IR transmitter" 8 | 9 | /* 10 | * ESPEasy plugin to send air conditioner / heatpump IR signals 11 | * * Use the device type 'Heatpump IR transmitter' as the device type in Devices -> Edit 12 | * * Connect and IR LED + series resistor between the GPIO pin configured for this device and ground 13 | * 14 | * Send commands through http, like this example (assuming the IP address of the ESP node is 192.168.0.61): 15 | * * curl http://192.168.0.61/control?cmd=heatpumpir,panasonic_ckp,1,1,0,22,0,0 16 | * 17 | * Send commands through OpenHAB MQTT with Mosquitto, like this example, 18 | * assuming the 'Name' of the ESP node in ESPEasy Main Settings page is 'newdevice') 19 | * * mosquitto_pub -t /newdevice/cmd -m heatpumpir,panasonic_ckp,1,1,0,22,0,0 20 | * 21 | * The parameters are (in this order) 22 | * * The type of the heatpump as a string, see the implementations of different models, like https://github.com/ToniA/arduino-heatpumpir/blob/master/MitsubishiHeatpumpIR.cpp 23 | * * power state (see https://github.com/ToniA/arduino-heatpumpir/blob/master/HeatpumpIR.h for modes) 24 | * * operating mode 25 | * * fan speed 26 | * * temperature 27 | * * vertical air direction 28 | * * horizontal air direction 29 | * 30 | * See the HeatpumpIR library for further information: https://github.com/ToniA/arduino-heatpumpir 31 | * 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | // Array with all supported heatpumps 52 | HeatpumpIR *heatpumpIR[] = {new PanasonicCKPHeatpumpIR(), new PanasonicDKEHeatpumpIR(), new PanasonicJKEHeatpumpIR(), 53 | new PanasonicNKEHeatpumpIR(), new CarrierNQVHeatpumpIR(), new CarrierMCAHeatpumpIR(), 54 | new MideaHeatpumpIR(), new FujitsuHeatpumpIR(), 55 | new MitsubishiFDHeatpumpIR(), new MitsubishiFEHeatpumpIR(), new MitsubishiMSYHeatpumpIR(), 56 | new SamsungAQVHeatpumpIR(), new SamsungFJMHeatpumpIR(), 57 | new SharpHeatpumpIR(), new DaikinHeatpumpIR(), 58 | new MitsubishiHeavyZJHeatpumpIR(), new MitsubishiHeavyZMHeatpumpIR(), 59 | new HyundaiHeatpumpIR(), new HisenseHeatpumpIR(), 60 | new GreeGenericHeatpumpIR(), new GreeYANHeatpumpIR(), 61 | new FuegoHeatpumpIR(), new ToshibaHeatpumpIR(), 62 | new HitachiHeatpumpIR(), 63 | NULL}; 64 | 65 | IRSender *Plugin_115_irSender; 66 | 67 | int panasonicCKPTimer = 0; 68 | 69 | boolean Plugin_115(byte function, struct EventStruct *event, String& string) 70 | { 71 | boolean success = false; 72 | 73 | switch (function) 74 | { 75 | case PLUGIN_DEVICE_ADD: 76 | { 77 | Device[++deviceCount].Number = PLUGIN_ID_115; 78 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 79 | Device[deviceCount].SendDataOption = false; 80 | break; 81 | } 82 | 83 | case PLUGIN_GET_DEVICENAME: 84 | { 85 | string = F(PLUGIN_NAME_115); 86 | break; 87 | } 88 | 89 | case PLUGIN_GET_DEVICEVALUENAMES: 90 | { 91 | break; 92 | } 93 | 94 | case PLUGIN_INIT: 95 | { 96 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 97 | if (irPin != -1) 98 | { 99 | addLog(LOG_LEVEL_INFO, "INIT: Heatpump IR transmitter activated"); 100 | if (Plugin_115_irSender != NULL) 101 | { 102 | delete Plugin_115_irSender; 103 | } 104 | Plugin_115_irSender = new IRSenderBitBang(irPin); 105 | } 106 | if (Plugin_115_irSender != 0 && irPin == -1) 107 | { 108 | addLog(LOG_LEVEL_INFO, "INIT: Heatpump IR transmitter deactivated"); 109 | delete Plugin_115_irSender; 110 | Plugin_115_irSender = NULL; 111 | } 112 | success = true; 113 | break; 114 | } 115 | 116 | case PLUGIN_WRITE: 117 | { 118 | String heatpumpModel; 119 | unsigned int powerMode = POWER_ON; 120 | unsigned int operatingMode = MODE_HEAT; 121 | unsigned int fanSpeed = FAN_2; 122 | unsigned int temperature = 22; 123 | unsigned int vDir = VDIR_UP; 124 | unsigned int hDir = HDIR_AUTO; 125 | char command[80]; 126 | command[0] = 0; 127 | char TmpStr1[80]; 128 | TmpStr1[0] = 0; 129 | string.toCharArray(command, 80); 130 | 131 | String tmpString = string; 132 | int argIndex = tmpString.indexOf(','); 133 | if (argIndex) tmpString = tmpString.substring(0, argIndex); 134 | 135 | if (tmpString.equalsIgnoreCase("HEATPUMPIR") && Plugin_115_irSender != NULL) 136 | { 137 | if (GetArgv(command, TmpStr1, 2)) heatpumpModel = TmpStr1; 138 | if (GetArgv(command, TmpStr1, 3)) powerMode = str2int(TmpStr1); 139 | if (GetArgv(command, TmpStr1, 4)) operatingMode = str2int(TmpStr1); 140 | if (GetArgv(command, TmpStr1, 5)) fanSpeed = str2int(TmpStr1); 141 | if (GetArgv(command, TmpStr1, 6)) temperature = str2int(TmpStr1); 142 | if (GetArgv(command, TmpStr1, 7)) vDir = str2int(TmpStr1); 143 | if (GetArgv(command, TmpStr1, 8)) hDir = str2int(TmpStr1); 144 | 145 | int i = 0; 146 | do 147 | { 148 | const char* shortName = heatpumpIR[i]->model(); 149 | const char* longName = heatpumpIR[i]->info(); 150 | 151 | if (strcmp_P(heatpumpModel.c_str(), shortName) == 0) 152 | { 153 | Serial.print(F("Found: ")); 154 | Serial.print(heatpumpModel); 155 | Serial.print(F(" as index: ")); 156 | Serial.println(i); 157 | 158 | heatpumpIR[i]->send(*Plugin_115_irSender, powerMode, operatingMode, fanSpeed, temperature, vDir, hDir); 159 | success = true; 160 | 161 | addLog(LOG_LEVEL_INFO, "Heatpump IR code transmitted"); 162 | if (printToWeb) 163 | { 164 | printWebString += F("Heatpump IR code transmitted"); 165 | } 166 | 167 | // Panasonic CKP can only be turned ON/OFF by using the timer, 168 | // so cancel the timer in 2 minutes, after the heatpump has turned on or off 169 | if (strcmp(heatpumpModel.c_str(), "panasonic_ckp") == 0) 170 | { 171 | panasonicCKPTimer = 120; 172 | } 173 | 174 | break; 175 | } 176 | } 177 | while (heatpumpIR[++i] != NULL); 178 | } 179 | break; 180 | } 181 | case PLUGIN_ONCE_A_SECOND: 182 | { 183 | if (panasonicCKPTimer > 0) 184 | { 185 | panasonicCKPTimer--; 186 | if (panasonicCKPTimer == 0) 187 | { 188 | PanasonicCKPHeatpumpIR *panasonicHeatpumpIR = new PanasonicCKPHeatpumpIR(); 189 | panasonicHeatpumpIR->sendPanasonicCKPCancelTimer(*Plugin_115_irSender); 190 | Serial.println("The TIMER led on Panasonic CKP should now be OFF"); 191 | } 192 | } 193 | break; 194 | } 195 | } 196 | return success; 197 | } 198 | -------------------------------------------------------------------------------- /_P116_ID12.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 116: Serial RFID ID-12 #################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_116 6 | #define PLUGIN_ID_116 116 7 | #define PLUGIN_NAME_116 "RFID Reader - ID12LA" 8 | #define PLUGIN_VALUENAME1_116 "Tag" 9 | 10 | boolean Plugin_116_init = false; 11 | 12 | boolean Plugin_116(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_116; 22 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 23 | Device[deviceCount].Ports = 0; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = false; 30 | Device[deviceCount].GlobalSyncOption = true; 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_116); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_116)); 43 | break; 44 | } 45 | 46 | 47 | case PLUGIN_INIT: 48 | { 49 | Plugin_116_init = true; 50 | Serial.begin(9600); 51 | success = true; 52 | break; 53 | } 54 | 55 | 56 | case PLUGIN_SERIAL_IN: 57 | { 58 | if (Plugin_116_init) 59 | { 60 | byte val = 0; 61 | byte code[6]; 62 | byte checksum = 0; 63 | byte bytesread = 0; 64 | byte tempbyte = 0; 65 | 66 | if ((val = Serial.read()) == 2) 67 | { // check for header 68 | bytesread = 0; 69 | while (bytesread < 12) { // read 10 digit code + 2 digit checksum 70 | if ( Serial.available() > 0) { 71 | val = Serial.read(); 72 | if ((val == 0x0D) || (val == 0x0A) || (val == 0x03) || (val == 0x02)) { 73 | // if header or stop bytes before the 10 digit reading 74 | break; 75 | } 76 | 77 | // Do Ascii/Hex conversion: 78 | if ((val >= '0') && (val <= '9')) { 79 | val = val - '0'; 80 | } 81 | else if ((val >= 'A') && (val <= 'F')) { 82 | val = 10 + val - 'A'; 83 | } 84 | 85 | // Every two hex-digits, add byte to code: 86 | if (bytesread & 1 == 1) { 87 | // make some space for this hex-digit by 88 | // shifting the previous hex-digit with 4 bits to the left: 89 | code[bytesread >> 1] = (val | (tempbyte << 4)); 90 | 91 | if (bytesread >> 1 != 5) { // If we're at the checksum byte, 92 | checksum ^= code[bytesread >> 1]; // Calculate the checksum... (XOR) 93 | }; 94 | } 95 | else { 96 | tempbyte = val; // Store the first hex digit first... 97 | }; 98 | bytesread++; // ready to read next digit 99 | } 100 | } 101 | } 102 | 103 | if (bytesread == 12) 104 | { 105 | if (code[5] == checksum) 106 | { 107 | // temp woraround, ESP Easy framework does not currently prepare this... 108 | byte index = 0; 109 | for (byte y = 0; y < TASKS_MAX; y++) 110 | if (Settings.TaskDeviceNumber[y] == PLUGIN_ID_116) 111 | index = y; 112 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[index]); 113 | event->TaskIndex = index; 114 | event->BaseVarIndex = index * VARS_PER_TASK; 115 | event->idx = Settings.TaskDeviceID[index]; 116 | event->sensorType = Device[DeviceIndex].VType; 117 | // endof workaround 118 | 119 | unsigned long key = 0; 120 | for (byte i = 1; i < 5; i++) key = key | (((unsigned long) code[i] << ((4 - i) * 8))); 121 | UserVar[event->BaseVarIndex] = (key & 0xFFFF); 122 | UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); 123 | String log = F("RFID : Tag: "); 124 | log += key; 125 | addLog(LOG_LEVEL_INFO, log); 126 | sendData(event); 127 | } 128 | } 129 | success = true; 130 | } 131 | break; 132 | } 133 | 134 | } 135 | return success; 136 | } 137 | 138 | -------------------------------------------------------------------------------- /_P119_BME680.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 119 BME680 I2C Temp/Hum/Barometric/Pressure/Gas Resistence Sensor ######## 3 | //####################################################################################################### 4 | 5 | /******************************************************************************* 6 | * Copyright 2017 7 | * Written by Rossen Tchobanski (rosko@rosko.net) 8 | * BSD license, all text above must be included in any redistribution 9 | * 10 | * Release notes: 11 | Adafruit_BME680 Library v1.0.5 required (https://github.com/adafruit/Adafruit_BME680/tree/1.0.5) 12 | /******************************************************************************/ 13 | 14 | 15 | //#ifdef PLUGIN_BUILD_DEV 16 | //#ifdef PLUGIN_BUILD_TESTING 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | 25 | #define PLUGIN_119 26 | #define PLUGIN_ID_119 119 27 | #define PLUGIN_NAME_119 "Environment - BME680" 28 | #define PLUGIN_VALUENAME1_119 "Temperature" 29 | #define PLUGIN_VALUENAME2_119 "Humidity" 30 | #define PLUGIN_VALUENAME3_119 "Pressure" 31 | #define PLUGIN_VALUENAME4_119 "Gas" 32 | 33 | #define BME_SCK 13 34 | #define BME_MISO 12 35 | #define BME_MOSI 11 36 | #define BME_CS 10 37 | 38 | #define SEALEVELPRESSURE_HPA (1013.25) 39 | 40 | Adafruit_BME680 bme; // I2C 41 | //Adafruit_BME680 bme(BME_CS); // hardware SPI 42 | //Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); 43 | 44 | 45 | boolean Plugin_119_init = false; 46 | 47 | boolean Plugin_119(byte function, struct EventStruct *event, String& string) 48 | { 49 | boolean success = false; 50 | 51 | switch (function) 52 | { 53 | case PLUGIN_DEVICE_ADD: 54 | { 55 | Device[++deviceCount].Number = PLUGIN_ID_119; 56 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 57 | Device[deviceCount].VType = SENSOR_TYPE_QUAD; 58 | Device[deviceCount].Ports = 0; 59 | Device[deviceCount].PullUpOption = false; 60 | Device[deviceCount].InverseLogicOption = false; 61 | Device[deviceCount].FormulaOption = true; 62 | Device[deviceCount].ValueCount = 4; 63 | Device[deviceCount].SendDataOption = true; 64 | Device[deviceCount].TimerOption = true; 65 | Device[deviceCount].GlobalSyncOption = true; 66 | break; 67 | } 68 | 69 | case PLUGIN_GET_DEVICENAME: 70 | { 71 | string = F(PLUGIN_NAME_119); 72 | break; 73 | } 74 | 75 | case PLUGIN_GET_DEVICEVALUENAMES: 76 | { 77 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_119)); 78 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_119)); 79 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_119)); 80 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_119)); 81 | break; 82 | } 83 | 84 | case PLUGIN_WEBFORM_LOAD: 85 | { 86 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 87 | /* 88 | String options[2]; 89 | options[0] = F("0x76 - default settings (SDO Low)"); 90 | options[1] = F("0x77 - alternate settings (SDO HIGH)"); 91 | */ 92 | int optionValues[2] = { 0x77, 0x76 }; 93 | addFormSelectorI2C(F("plugin_119_BME680_i2c"), 2, optionValues, choice); 94 | addFormNote(F("SDO Low=0x76, High=0x77")); 95 | 96 | addFormNumericBox(F("Altitude"), F("plugin_119_BME680_elev"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 97 | addUnit(F("m")); 98 | 99 | success = true; 100 | break; 101 | } 102 | 103 | case PLUGIN_WEBFORM_SAVE: 104 | { 105 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_119_BME680_i2c")); 106 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_119_BME680_elev")); 107 | success = true; 108 | break; 109 | } 110 | 111 | case PLUGIN_READ: 112 | { 113 | 114 | 115 | 116 | if (!Plugin_119_init) 117 | { 118 | addLog(LOG_LEVEL_INFO, F("BME680 : init")); 119 | 120 | Plugin_119_init = bme.begin(); 121 | 122 | // Set up oversampling and filter initialization 123 | bme.setTemperatureOversampling(BME680_OS_8X); 124 | bme.setHumidityOversampling(BME680_OS_2X); 125 | bme.setPressureOversampling(BME680_OS_4X); 126 | bme.setIIRFilterSize(BME680_FILTER_SIZE_3); 127 | bme.setGasHeater(320, 150); // 320*C for 150 ms 128 | 129 | success = true; 130 | break; 131 | } 132 | 133 | if (Plugin_119_init) 134 | { 135 | if (! bme.performReading()) { 136 | addLog(LOG_LEVEL_ERROR, F("BME680 : Failed to perform reading!")); 137 | success = false; 138 | break; 139 | } 140 | 141 | UserVar[event->BaseVarIndex + 0] = bme.temperature; 142 | UserVar[event->BaseVarIndex + 1] = bme.humidity; 143 | UserVar[event->BaseVarIndex + 2] = bme.pressure / 100.0; 144 | UserVar[event->BaseVarIndex + 3] = bme.gas_resistance / 1000.0; 145 | 146 | } 147 | 148 | success = true; 149 | break; 150 | } 151 | 152 | } 153 | return success; 154 | } 155 | 156 | //#endif 157 | -------------------------------------------------------------------------------- /_P122_NeoPixel.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 122: NeoPixel clock ####################################### 3 | //####################################################################################################### 4 | 5 | // Command: NeoPixel ,,, 6 | 7 | #include 8 | Adafruit_NeoPixel *Plugin_122_pixels; 9 | 10 | #define PLUGIN_122 11 | #define PLUGIN_ID_122 122 12 | #define PLUGIN_NAME_122 "NeoPixel Basic" 13 | #define PLUGIN_VALUENAME1_122 "" 14 | boolean Plugin_122(byte function, struct EventStruct *event, String& string) 15 | { 16 | boolean success = false; 17 | 18 | switch (function) 19 | { 20 | 21 | case PLUGIN_DEVICE_ADD: 22 | { 23 | Device[++deviceCount].Number = PLUGIN_ID_122; 24 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 25 | Device[deviceCount].Custom = true; 26 | Device[deviceCount].TimerOption = false; 27 | break; 28 | } 29 | 30 | case PLUGIN_GET_DEVICENAME: 31 | { 32 | string = F(PLUGIN_NAME_122); 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICEVALUENAMES: 37 | { 38 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_122)); 39 | break; 40 | } 41 | 42 | case PLUGIN_WEBFORM_LOAD: 43 | { 44 | char tmpString[128]; 45 | sprintf_P(tmpString, PSTR("Led Count:"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 46 | string += tmpString; 47 | 48 | string += F("GPIO:"); 49 | addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]); 50 | 51 | success = true; 52 | break; 53 | } 54 | 55 | case PLUGIN_WEBFORM_SAVE: 56 | { 57 | String plugin1 = WebServer.arg(F("plugin_122_leds")); 58 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 59 | success = true; 60 | break; 61 | } 62 | 63 | case PLUGIN_INIT: 64 | { 65 | if (!Plugin_122_pixels) 66 | { 67 | Plugin_122_pixels = new Adafruit_NeoPixel(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePin1[event->TaskIndex], NEO_GRB + NEO_KHZ800); 68 | Plugin_122_pixels->begin(); // This initializes the NeoPixel library. 69 | } 70 | success = true; 71 | break; 72 | } 73 | 74 | case PLUGIN_WRITE: 75 | { 76 | if (Plugin_122_pixels) 77 | { 78 | String tmpString = string; 79 | int argIndex = tmpString.indexOf(','); 80 | if (argIndex) 81 | tmpString = tmpString.substring(0, argIndex); 82 | 83 | if (tmpString.equalsIgnoreCase(F("NeoPixel"))) 84 | { 85 | char Line[80]; 86 | char TmpStr1[80]; 87 | TmpStr1[0] = 0; 88 | string.toCharArray(Line, 80); 89 | int Par4 = 0; 90 | if (GetArgv(Line, TmpStr1, 5)) Par4 = str2int(TmpStr1); 91 | Plugin_122_pixels->setPixelColor(event->Par1 - 1, Plugin_122_pixels->Color(event->Par2, event->Par3, Par4)); 92 | Plugin_122_pixels->show(); // This sends the updated pixel color to the hardware. 93 | success = true; 94 | } 95 | } 96 | break; 97 | } 98 | 99 | } 100 | return success; 101 | } 102 | 103 | -------------------------------------------------------------------------------- /_P126_Ping.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 126: Ping IP (non-blocking) ############################### 3 | //####################################################################################################### 4 | // Plugin originally created by Neutrino 5 | // Updated by Alexander Nagy ( https://bitekmindenhol.blog.hu/ ) 6 | // 7 | // Used Library: https://github.com/bluemurder/esp8266-ping by Alessio Leoncini 8 | // 9 | 10 | #define PLUGIN_126 11 | #define PLUGIN_ID_126 126 12 | #define PLUGIN_NAME_126 "Network - Ping IP Device" 13 | #define PLUGIN_VALUENAME1_126 "Ping" 14 | 15 | #include // ESP8266-ping 16 | 17 | #define P126_MaxInstances 3 // maximal allowed number of P126 devices 18 | Pinger p126_pinger[P126_MaxInstances]; 19 | 20 | boolean Plugin_126_init[P126_MaxInstances]; 21 | 22 | boolean Plugin_126(byte function, struct EventStruct *event, String& string) 23 | { 24 | boolean success = false; 25 | 26 | switch (function) 27 | { 28 | 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_126; 32 | Device[deviceCount].Type = DEVICE_TYPE_DUMMY; 33 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 34 | Device[deviceCount].Ports = 0; 35 | Device[deviceCount].PullUpOption = false; 36 | Device[deviceCount].ValueCount = 1; 37 | Device[deviceCount].SendDataOption = true; 38 | Device[deviceCount].TimerOption = true; 39 | Device[deviceCount].GlobalSyncOption = true; 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICENAME: 44 | { 45 | string = F(PLUGIN_NAME_126); 46 | break; 47 | } 48 | 49 | case PLUGIN_GET_DEVICEVALUENAMES: 50 | { 51 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_126)); 52 | break; 53 | } 54 | 55 | case PLUGIN_WEBFORM_LOAD: 56 | { 57 | addFormNumericBox(F("IP 1st octet"), F("plugin_126_1"), Settings.TaskDevicePluginConfig[event->TaskIndex][1], 1, 254); 58 | addFormNumericBox(F("IP 2nd octet"), F("plugin_126_2"), Settings.TaskDevicePluginConfig[event->TaskIndex][2], 0, 255); 59 | addFormNumericBox(F("IP 3rd octet"), F("plugin_126_3"), Settings.TaskDevicePluginConfig[event->TaskIndex][3], 0, 255); 60 | addFormNumericBox(F("IP 4th octet"), F("plugin_126_4"), Settings.TaskDevicePluginConfig[event->TaskIndex][4], 1, 254); 61 | success = true; 62 | break; 63 | } 64 | 65 | case PLUGIN_WEBFORM_SAVE: 66 | { 67 | LoadTaskSettings(event->TaskIndex); 68 | byte baseaddr = 0; 69 | for (byte TaskIndex = 0; TaskIndex < event->TaskIndex; TaskIndex++) 70 | { 71 | if (Settings.TaskDeviceNumber[TaskIndex] == PLUGIN_ID_126) { 72 | baseaddr = baseaddr + 1; 73 | } 74 | } 75 | success = false; 76 | if (baseaddr < P126_MaxInstances) { 77 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = baseaddr; 78 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_126_1")); 79 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_126_2")); 80 | Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_126_3")); 81 | Settings.TaskDevicePluginConfig[event->TaskIndex][4] = getFormItemInt(F("plugin_126_4")); 82 | success = true; 83 | } else { 84 | Settings.TaskDeviceEnabled[event->TaskIndex] = false; 85 | String log = F("Maximum number of Ping devices reached! "); 86 | log += String(baseaddr); 87 | addLog(LOG_LEVEL_INFO, log); 88 | } 89 | break; 90 | } 91 | 92 | case PLUGIN_INIT: 93 | { 94 | LoadTaskSettings(event->TaskIndex); 95 | byte baseaddr = 0; 96 | for (byte TaskIndex = 0; TaskIndex < event->TaskIndex; TaskIndex++) 97 | { 98 | if (Settings.TaskDeviceNumber[TaskIndex] == PLUGIN_ID_126) { 99 | baseaddr = baseaddr + 1; 100 | } 101 | } 102 | success = false; 103 | if (baseaddr < P126_MaxInstances) { 104 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = baseaddr; 105 | success = true; 106 | Plugin_126_init[baseaddr] = true; 107 | } else { 108 | Settings.TaskDeviceEnabled[event->TaskIndex] = false; 109 | String log = F("Maximum number of Ping devices reached! "); 110 | log += String(baseaddr); 111 | addLog(LOG_LEVEL_INFO, log); 112 | } 113 | break; 114 | } 115 | 116 | case PLUGIN_READ: 117 | { 118 | success = false; 119 | bool ret = false; 120 | LoadTaskSettings(event->TaskIndex); 121 | byte cpy = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 122 | if (cpy < P126_MaxInstances) { 123 | if (Plugin_126_init[cpy]) 124 | { 125 | if ((Settings.TaskDevicePluginConfig[event->TaskIndex][1] > 0) and (Settings.TaskDevicePluginConfig[event->TaskIndex][4] > 0)) { 126 | IPAddress ip( Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][2], Settings.TaskDevicePluginConfig[event->TaskIndex][3], Settings.TaskDevicePluginConfig[event->TaskIndex][4] ); // The remote ip to ping 127 | String log = F("Ping "); 128 | ret = p126_pinger[cpy].Ping(ip, 3, 100); // 3 probe, 100millisec timeout 129 | p126_pinger[cpy].OnEnd([](const PingerResponse & response) 130 | { 131 | for (byte TaskIndex = 0; TaskIndex < TASKS_MAX; TaskIndex++) 132 | { 133 | if (Settings.TaskDeviceNumber[TaskIndex] == PLUGIN_ID_126) { 134 | if ( 135 | (response.DestIPAddress[0] == Settings.TaskDevicePluginConfig[TaskIndex][1]) and 136 | (response.DestIPAddress[1] == Settings.TaskDevicePluginConfig[TaskIndex][2]) and 137 | (response.DestIPAddress[2] == Settings.TaskDevicePluginConfig[TaskIndex][3]) and 138 | (response.DestIPAddress[3] == Settings.TaskDevicePluginConfig[TaskIndex][4])) { 139 | UserVar[(TaskIndex * VARS_PER_TASK)] = (response.TotalReceivedResponses > 0); 140 | break; 141 | } 142 | 143 | } 144 | } 145 | 146 | String logs = F("Ping result for:"); 147 | logs += response.DestIPAddress.toString().c_str(); 148 | logs += F(" "); 149 | logs += String(response.TotalReceivedResponses); 150 | addLog(LOG_LEVEL_DEBUG, logs); 151 | return true; 152 | }); 153 | success = true; 154 | } 155 | } 156 | } 157 | break; 158 | } 159 | 160 | } 161 | return success; 162 | } 163 | -------------------------------------------------------------------------------- /_P129_RC522_RFID.ino: -------------------------------------------------------------------------------- 1 | #ifdef USES_P129 2 | //####################################################################################################### 3 | //################################ Plugin-214: RC522 SPI RFID reader #################################### 4 | //####################################################################################################### 5 | 6 | #define PLUGIN_129 7 | #define PLUGIN_ID_129 129 8 | #define PLUGIN_NAME_129 "RFID - RC522 SPI" 9 | #define PLUGIN_VALUENAME1_129 "Tag" 10 | #define PLUGIN_129_CS 16 11 | 12 | #include 13 | #include 14 | 15 | MFRC522 mfrc522; 16 | 17 | uint8_t Plugin_129_packetbuffer[64]; 18 | uint8_t Plugin_129_command; 19 | 20 | boolean Plugin_129(byte function, struct EventStruct *event, String& string) 21 | { 22 | boolean success = false; 23 | 24 | 25 | 26 | switch (function) 27 | { 28 | 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_129; 32 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 33 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 34 | Device[deviceCount].Ports = 0; 35 | Device[deviceCount].PullUpOption = false; 36 | Device[deviceCount].InverseLogicOption = false; 37 | Device[deviceCount].ValueCount = 1; 38 | Device[deviceCount].SendDataOption = true; 39 | Device[deviceCount].TimerOption = false; 40 | Device[deviceCount].GlobalSyncOption = true; 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICENAME: 45 | { 46 | string = F(PLUGIN_NAME_129); 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICEVALUENAMES: 51 | { 52 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_129)); 53 | break; 54 | } 55 | 56 | case PLUGIN_WEBFORM_LOAD: 57 | { 58 | addFormPinSelect(string, F("Reset Pin"), F("taskdevicepin3"), Settings.TaskDevicePin3[event->TaskIndex]); 59 | success = true; 60 | break; 61 | } 62 | 63 | case PLUGIN_INIT: 64 | { 65 | 66 | for(byte x=0; x < 3; x++) 67 | { 68 | String log = F("MFRC522: Init"); 69 | addLog(LOG_LEVEL_INFO, log); 70 | if(Plugin_129_Init(Settings.TaskDevicePin1[event->TaskIndex],Settings.TaskDevicePin3[event->TaskIndex])) 71 | break; 72 | delay(1000); 73 | } 74 | break; 75 | } 76 | 77 | case PLUGIN_TEN_PER_SECOND: 78 | { 79 | static unsigned long tempcounter = 0; 80 | static byte counter; 81 | static byte errorCount=0; 82 | 83 | counter++; 84 | if (counter == 3) 85 | { 86 | counter = 0; 87 | uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; 88 | uint8_t uidLength; 89 | byte error = Plugin_129_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength); 90 | 91 | if (error == 1) 92 | { 93 | errorCount++; 94 | String log = F("MFRC522: Read error: "); 95 | log += errorCount; 96 | addLog(LOG_LEVEL_ERROR, log); 97 | } 98 | else 99 | errorCount=0; 100 | 101 | if (errorCount > 2) // if three consecutive I2C errors, reset PN532 102 | { 103 | Plugin_129_Init(Settings.TaskDevicePin1[event->TaskIndex],Settings.TaskDevicePin3[event->TaskIndex]); 104 | } 105 | 106 | if (error == 0) { 107 | unsigned long key = uid[0]; 108 | for (uint8_t i = 1; i < 4; i++) { 109 | key <<= 8; 110 | key += uid[i]; 111 | } 112 | UserVar[event->BaseVarIndex] = (key & 0xFFFF); 113 | UserVar[event->BaseVarIndex + 1] = ((key >> 16) & 0xFFFF); 114 | String log = F("MFRC522: Tag: "); 115 | log += key; 116 | tempcounter++; 117 | log += " "; 118 | log += tempcounter; 119 | addLog(LOG_LEVEL_INFO, log); 120 | sendData(event); 121 | } 122 | } 123 | break; 124 | } 125 | } 126 | return success; 127 | } 128 | 129 | 130 | /*********************************************************************************************\ 131 | * MFRC522 init 132 | \*********************************************************************************************/ 133 | boolean Plugin_129_Init(int8_t csPin, int8_t resetPin) 134 | { 135 | if (resetPin != -1) 136 | { 137 | String log = F("MFRC522: Reset on pin: "); 138 | log += resetPin; 139 | addLog(LOG_LEVEL_INFO, log); 140 | pinMode(resetPin, OUTPUT); 141 | digitalWrite(resetPin, LOW); 142 | delay(100); 143 | digitalWrite(resetPin, HIGH); 144 | pinMode(resetPin, INPUT_PULLUP); 145 | delay(10); 146 | } 147 | 148 | pinMode(csPin, OUTPUT); 149 | digitalWrite(csPin, LOW); 150 | 151 | 152 | mfrc522.PCD_Init(csPin,resetPin); // Init MFRC522 module 153 | 154 | //If you set Antenna Gain to Max it will increase reading distance 155 | mfrc522.PCD_SetAntennaGain(mfrc522.RxGain_max); 156 | 157 | bool result = mfrc522.PCD_PerformSelfTest(); // perform the test 158 | 159 | if (result) { 160 | //String log = F("RC522: Found"); 161 | // Get the MFRC522 software version 162 | byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); 163 | 164 | // When 0x00 or 0xFF is returned, communication probably failed 165 | if ((v == 0x00) || (v == 0xFF)) { 166 | String log=F("MFRC522: Communication failure, is the MFRC522 properly connected?"); 167 | addLog(LOG_LEVEL_ERROR,log); 168 | return false; 169 | } 170 | else 171 | { 172 | String log=F("MFRC522: Software Version: "); 173 | if (v == 0x91) 174 | log+=F(" = v1.0"); 175 | else if (v == 0x92) 176 | log+=F(" = v2.0"); 177 | else 178 | log+=F(" (unknown),probably a chinese clone?"); 179 | 180 | addLog(LOG_LEVEL_INFO, log); 181 | } 182 | } 183 | else 184 | return false; 185 | 186 | return true; 187 | } 188 | 189 | 190 | 191 | 192 | /*********************************************************************************************\ 193 | * RC522 read tag ID 194 | \*********************************************************************************************/ 195 | byte Plugin_129_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength) 196 | { 197 | // Getting ready for Reading PICCs 198 | if ( ! mfrc522.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue 199 | return 2; 200 | } 201 | String log = F("MFRC522: New Card Detected"); 202 | addLog(LOG_LEVEL_INFO,log); 203 | if ( ! mfrc522.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue 204 | return 1; 205 | } 206 | 207 | // There are Mifare PICCs which have 4 byte or 7 byte UID care if you use 7 byte PICC 208 | // I think we should assume every PICC as they have 4 byte UID 209 | // Until we support 7 byte PICCs 210 | log =F("MFRC522: Scanned PICC's UID"); 211 | addLog(LOG_LEVEL_INFO,log); 212 | for ( uint8_t i = 0; i < 4; i++) { // 213 | uid[i] = mfrc522.uid.uidByte[i]; 214 | //Serial.print(readCard[i], HEX); 215 | } 216 | *uidLength = 4; 217 | mfrc522.PICC_HaltA(); // Stop reading 218 | return 0; 219 | 220 | } 221 | 222 | 223 | #endif // USES_P129 224 | -------------------------------------------------------------------------------- /_P131_SHT3X.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 131: SHT30/SHT31/SHT35 Temp/Humidity Sensor ############################### 3 | //####################################################################################################### 4 | 5 | class SHT3X{ 6 | public: 7 | SHT3X(uint8_t address); 8 | void get(void); 9 | float cTemp=0; 10 | // float fTemp=0; 11 | float humidity=0; 12 | 13 | private: 14 | uint8_t _address; 15 | }; 16 | 17 | #define PLUGIN_131 18 | #define PLUGIN_ID_131 131 19 | #define PLUGIN_NAME_131 "Temperature & Humidity - SHT3X" 20 | #define PLUGIN_VALUENAME1_131 "Temperature" 21 | #define PLUGIN_VALUENAME2_131 "Humidity" 22 | 23 | boolean Plugin_131_init = false; 24 | 25 | uint8_t addr=0x45; 26 | SHT3X sht30(addr); 27 | 28 | boolean Plugin_131(byte function, struct EventStruct *event, String& string) 29 | { 30 | boolean success = false; 31 | 32 | switch (function) 33 | { 34 | case PLUGIN_DEVICE_ADD: 35 | { 36 | Device[++deviceCount].Number = PLUGIN_ID_131; 37 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 38 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 39 | Device[deviceCount].Ports = 0; 40 | Device[deviceCount].PullUpOption = false; 41 | Device[deviceCount].InverseLogicOption = false; 42 | Device[deviceCount].FormulaOption = true; 43 | Device[deviceCount].ValueCount = 2; 44 | Device[deviceCount].SendDataOption = true; 45 | Device[deviceCount].TimerOption = true; 46 | Device[deviceCount].GlobalSyncOption = true; 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICENAME: 51 | { 52 | string = F(PLUGIN_NAME_131); 53 | break; 54 | } 55 | 56 | case PLUGIN_GET_DEVICEVALUENAMES: 57 | { 58 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_131)); 59 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_131)); 60 | break; 61 | } 62 | 63 | case PLUGIN_INIT: 64 | { 65 | Plugin_131_init = true; 66 | success = true; 67 | break; 68 | } 69 | 70 | case PLUGIN_READ: 71 | { 72 | if (!Plugin_131_init) { 73 | String log = F("SHT3X : not yet initialized!"); 74 | addLog(LOG_LEVEL_ERROR, log); 75 | break; 76 | } 77 | sht30.get(); 78 | UserVar[event->BaseVarIndex] = sht30.cTemp; 79 | UserVar[event->BaseVarIndex+1] = sht30.humidity; 80 | String log = F("SHT3X: Temperature: "); 81 | log += UserVar[event->BaseVarIndex]; 82 | log += F(" Humidity: "); 83 | log += UserVar[event->BaseVarIndex + 1]; 84 | addLog(LOG_LEVEL_INFO, log); 85 | success = true; 86 | break; 87 | } 88 | } 89 | return success; 90 | } 91 | 92 | SHT3X::SHT3X(uint8_t address) 93 | { 94 | Wire.begin(); 95 | _address=address; 96 | } 97 | 98 | void SHT3X::get() 99 | { 100 | unsigned int data[6]; 101 | 102 | // Start I2C Transmission 103 | Wire.beginTransmission(_address); 104 | // Send measurement command 105 | Wire.write(0x2C); 106 | Wire.write(0x06); 107 | // Stop I2C transmission 108 | Wire.endTransmission(); 109 | delay(500); 110 | 111 | // Request 6 bytes of data 112 | Wire.requestFrom(_address, 6); 113 | 114 | // Read 6 bytes of data 115 | // cTemp msb, cTemp lsb, cTemp crc, humidity msb, humidity lsb, humidity crc 116 | if (Wire.available() == 6) 117 | { 118 | data[0] = Wire.read(); 119 | data[1] = Wire.read(); 120 | data[2] = Wire.read(); 121 | data[3] = Wire.read(); 122 | data[4] = Wire.read(); 123 | data[5] = Wire.read(); 124 | } 125 | 126 | // Convert the data 127 | cTemp = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45; 128 | // fTemp = (cTemp * 1.8) + 32; 129 | humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0); 130 | } 131 | -------------------------------------------------------------------------------- /_P133_VL53L0X.ino: -------------------------------------------------------------------------------- 1 | #ifdef USES_P133 2 | //####################################################################################################### 3 | //########################### Plugin 133 VL53L0X I2C Ranging LIDAR ################################# 4 | //####################################################################################################### 5 | //###################################### stefan@clumsy.ch ########################################## 6 | //####################################################################################################### 7 | 8 | 9 | // needs VL53L0X library from pololu https://github.com/pololu/vl53l0x-arduino 10 | 11 | 12 | 13 | #define PLUGIN_133 14 | #define PLUGIN_ID_133 133 15 | #define PLUGIN_NAME_133 "Distance - VL53L0X [TESTING]" 16 | #define PLUGIN_VALUENAME1_133 "Distance" 17 | 18 | 19 | #include 20 | #include 21 | 22 | VL53L0X sensor; 23 | 24 | //////////////////////////// 25 | // VL53L0X Command Codes // 26 | //////////////////////////// 27 | 28 | boolean Plugin_133_init[2] = {false, false}; 29 | 30 | boolean Plugin_133(byte function, struct EventStruct *event, String& string) 31 | { 32 | boolean success = false; 33 | 34 | switch (function) 35 | { 36 | case PLUGIN_DEVICE_ADD: 37 | { 38 | Device[++deviceCount].Number = PLUGIN_ID_133; 39 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 40 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 41 | Device[deviceCount].Ports = 0; 42 | Device[deviceCount].PullUpOption = false; 43 | Device[deviceCount].InverseLogicOption = false; 44 | Device[deviceCount].FormulaOption = true; 45 | Device[deviceCount].ValueCount = 1; 46 | Device[deviceCount].SendDataOption = true; 47 | Device[deviceCount].TimerOption = true; 48 | Device[deviceCount].GlobalSyncOption = true; 49 | break; 50 | } 51 | 52 | case PLUGIN_GET_DEVICENAME: 53 | { 54 | string = F(PLUGIN_NAME_133); 55 | break; 56 | } 57 | 58 | case PLUGIN_GET_DEVICEVALUENAMES: 59 | { 60 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_133)); 61 | break; 62 | } 63 | case PLUGIN_WEBFORM_LOAD: 64 | { 65 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 66 | int optionValues[2] = { 0x29, 0x30 }; 67 | addFormSelectorI2C(F("plugin_133_vl53l0x_i2c"), 2, optionValues, choice); 68 | addFormNote(F("SDO Low=0x29, High=0x30")); 69 | 70 | unsigned int choiceMode2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 71 | String optionsMode2[3]; 72 | optionsMode2[0] = F("VL53L0X_NORMAL_TIMING"); 73 | optionsMode2[1] = F("VL53L0X_FAST_TIMING"); 74 | optionsMode2[2] = F("VL53L0X_ACCURATE_TIMING"); 75 | int optionValuesMode2[3]; 76 | optionValuesMode2[0] = 80; 77 | optionValuesMode2[1] = 20; 78 | optionValuesMode2[2] = 320; 79 | addFormSelector(F("Timing"), F("plugin_133_vl53l0x_timing"), 3, optionsMode2, optionValuesMode2, choiceMode2); 80 | 81 | boolean choiceMode3 = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 82 | String optionsMode3[2]; 83 | optionsMode3[0] = F("VL53L0X_NORMAL_RANGE"); 84 | optionsMode3[1] = F("VL53L0X_LONG_RANGE"); 85 | int optionValuesMode3[2]; 86 | optionValuesMode3[0] = 0; 87 | optionValuesMode3[1] = 1; 88 | addFormSelector(F("Range"), F("plugin_133_vl53l0x_range"), 2, optionsMode3, optionValuesMode3, choiceMode3); 89 | 90 | success = true; 91 | break; 92 | } 93 | 94 | case PLUGIN_WEBFORM_SAVE: 95 | { 96 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_133_vl53l0x_i2c")); 97 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_133_vl53l0x_timing")); 98 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_133_vl53l0x_range")); 99 | 100 | Plugin_133_init[Settings.TaskDevicePluginConfig[event->TaskIndex][0]] = false; 101 | success = true; 102 | break; 103 | } 104 | 105 | case PLUGIN_READ: 106 | { 107 | 108 | int idx = Settings.TaskDevicePluginConfig[event->TaskIndex][0] ; 109 | // Plugin_133_init[idx] &= Plugin_133_check(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); // Check id device is present 110 | 111 | // IT = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; // set Integration Time 112 | 113 | if (!Plugin_133_init[idx]) 114 | { 115 | Plugin_133_init[idx] = Plugin_133_begin(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][2]); 116 | } 117 | 118 | 119 | String log = F("VL53L0X : idx: 0x"); 120 | log += String(idx, HEX); 121 | addLog(LOG_LEVEL_DEBUG, log); 122 | log = F("VL53L0X : plugin(idx): 0x"); 123 | log += String(Plugin_133_init[idx], HEX); 124 | addLog(LOG_LEVEL_DEBUG, log); 125 | 126 | if (Plugin_133_init[idx]) 127 | { 128 | success = true; 129 | long dist = sensor.readRangeSingleMillimeters(); 130 | if (sensor.timeoutOccurred()) { 131 | addLog(LOG_LEVEL_DEBUG, "VL53L0X: TIMEOUT"); 132 | success = false; 133 | } else if ( dist >= 8190 ) { 134 | addLog(LOG_LEVEL_DEBUG, "VL53L0X: NO MEASUREMENT"); 135 | success = false; 136 | } else { 137 | UserVar[event->BaseVarIndex] = dist; 138 | } 139 | 140 | addLog(LOG_LEVEL_DEBUG, log); 141 | log = F("VL53L0X: Address: 0x"); 142 | log += String(Settings.TaskDevicePluginConfig[event->TaskIndex][0], HEX); 143 | log += F(" / Timing: "); 144 | log += String(Settings.TaskDevicePluginConfig[event->TaskIndex][1], DEC); 145 | log += F(" / Long Range: "); 146 | log += String(Settings.TaskDevicePluginConfig[event->TaskIndex][2], BIN); 147 | log += F(" / Distance: "); 148 | log += UserVar[event->BaseVarIndex]; 149 | addLog(LOG_LEVEL_INFO, log); 150 | 151 | } 152 | break; 153 | } 154 | 155 | } 156 | return success; 157 | } 158 | 159 | //**************************************************************************/ 160 | // Check VL53L0X presence 161 | //**************************************************************************/ 162 | /*bool Plugin_133_check(int a) { 163 | vl53l0x_i2caddr = a ? a : 0x29; 164 | bool wire_status = false; 165 | uint16_t deviceID = Plugin_133_getVL53L0XID(a); 166 | 167 | String log = F("VL53L0X : ID: 0x"); 168 | log += String(deviceID, HEX); 169 | addLog(LOG_LEVEL_DEBUG, log); 170 | 171 | if (deviceID != 0x29) { 172 | return false; 173 | } else { 174 | return true; 175 | } 176 | } 177 | */ 178 | 179 | //**************************************************************************/ 180 | // Initialize VL53L0X 181 | //**************************************************************************/ 182 | bool Plugin_133_begin(int a, int timing, boolean range) { 183 | /* 184 | if (! Plugin_133_check(a)) 185 | return false; 186 | */ 187 | 188 | sensor.init(); 189 | sensor.setTimeout(500); 190 | 191 | if ( range ) { 192 | // lower the return signal rate limit (default is 0.25 MCPS) 193 | sensor.setSignalRateLimit(0.1); 194 | // increase laser pulse periods (defaults are 14 and 10 PCLKs) 195 | sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodPreRange, 18); 196 | sensor.setVcselPulsePeriod(VL53L0X::VcselPeriodFinalRange, 14); 197 | } 198 | 199 | sensor.setMeasurementTimingBudget(timing * 1000); 200 | 201 | delay(timing + 50); 202 | 203 | return true; 204 | } 205 | 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /_P143_AnyonePresent.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 146: Presence ############################################# 3 | //####################################################################################################### 4 | // written by Jochen Krapf (jk@nerd2nerd.org) 5 | 6 | /* 7 | EN: The recognition of whether a person is in a room is more difficult than one often thinks. It helps if several different sensors are used (e.g., PIR, radar, light barrier, brightness, noise). However, since the sensors only emit short pulses for many pulses, many data are sent to controllers (e.g., MQTT), and the smart home system must recombine these data through complex rules to a steady "someone there". 8 | This plugin listens for up to 3 sensors and triggers a "someone there" when a sensor responds. A "Nobody there" is not sent until all 3 sensors are silent for the set time (Presence Time). A filter prevents unwanted triggering by ESD pulses. 9 | An analog sensor can also be connected. The absolute value of the analog voltage at AIN is irrelevant. The plugin responds to quick changes of the values. 10 | 11 | DE: Die Erkennung ob sich eine Person in einem Raum befindet ist schwieriger als man oftmals denkt. Es hilft, wenn man mehrere unterschiedliche Sensoren einsetzt (z.B. PIR, Radar, Lichtschranke, Helligkeit, Geräusch). Da jedoch die Sensoren nur kurze dafür viele Impulse abgeben werden viele Daten an Controller (z.B. MQTT) gesendet und das Smart-Home-System muss diese Daten über aufwendige Regeln wieder zu einem stetigen „Jemand da“ zusammenfassen. 12 | Dieses Plugin lauscht auf bis zu 3 Sensoren und triggert ein „Jemand da“ wenn ein Sensor anspricht. Ein „Keiner da“ wird erst gesendet, wenn alle 3 Sensoren für die eingestellte Zeit (Presence Time) schweigen. Ein Filter verhindert das ungewollte triggern durch ESD-Impulse. 13 | Es kann auch ein analoger Sensor angeschlossen werden. Der Absolutwert der Analog-Spannung an AIN spielt dabei keine Rolle. Das Plugin reagiert auf schnelle Änderungen der Werte. 14 | */ 15 | 16 | #ifdef PLUGIN_BUILD_TESTING 17 | 18 | 19 | //#include <*.h> - no external lib required 20 | 21 | #define PLUGIN_143 22 | #define PLUGIN_ID_143 143 23 | #define PLUGIN_NAME_143 "Anyone Present" 24 | #define PLUGIN_VALUENAME1_143 "Presence" 25 | 26 | static long Plugin_143_millisPresenceEnd = 0; 27 | static long Plugin_143_millisPresenceTime = 10000; 28 | 29 | static int Plugin_143_pin[3] = {-1,-1,-1}; 30 | static byte Plugin_143_lowActive = false; 31 | static byte Plugin_143_useAin = false; 32 | static byte Plugin_143_counter[3] = {0,0,0}; 33 | 34 | 35 | boolean Plugin_143(byte function, struct EventStruct *event, String& string) 36 | { 37 | boolean success = false; 38 | 39 | switch (function) 40 | { 41 | case PLUGIN_DEVICE_ADD: 42 | { 43 | Device[++deviceCount].Number = PLUGIN_ID_143; 44 | Device[deviceCount].Type = DEVICE_TYPE_TRIPLE; 45 | Device[deviceCount].Ports = 0; 46 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 47 | Device[deviceCount].PullUpOption = true; 48 | Device[deviceCount].InverseLogicOption = true; 49 | Device[deviceCount].FormulaOption = false; 50 | Device[deviceCount].ValueCount = 1; 51 | Device[deviceCount].SendDataOption = true; 52 | Device[deviceCount].TimerOption = true; 53 | Device[deviceCount].TimerOptional = true; 54 | Device[deviceCount].GlobalSyncOption = true; 55 | break; 56 | } 57 | 58 | case PLUGIN_GET_DEVICENAME: 59 | { 60 | string = F(PLUGIN_NAME_143); 61 | break; 62 | } 63 | 64 | case PLUGIN_GET_DEVICEVALUENAMES: 65 | { 66 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_143)); 67 | break; 68 | } 69 | 70 | case PLUGIN_WEBFORM_LOAD: 71 | { 72 | //default values 73 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] <= 0) //Plugin_143_millisPresenceTime 74 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = 60; 75 | 76 | addFormCheckBox(string, F("Use Analog Input"), F("useain"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 77 | 78 | addFormNumericBox(string, F("Presence Time"), F("ptime"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 79 | addUnit(string, F("sec")); 80 | 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_WEBFORM_SAVE: 86 | { 87 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("ptime")); 88 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = isFormItemChecked(F("useain")); 89 | 90 | success = true; 91 | break; 92 | } 93 | 94 | case PLUGIN_INIT: 95 | { 96 | Plugin_143_lowActive = Settings.TaskDevicePin1Inversed[event->TaskIndex]; 97 | Plugin_143_millisPresenceTime = Settings.TaskDevicePluginConfig[event->TaskIndex][0] * 1000; 98 | Plugin_143_useAin = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 99 | 100 | String log = F("Any1 : GPIO: "); 101 | for (byte i=0; i<3; i++) 102 | { 103 | int pin = Settings.TaskDevicePin[i][event->TaskIndex]; 104 | Plugin_143_pin[i] = pin; 105 | if (pin >= 0) 106 | { 107 | pinMode(pin, (Settings.TaskDevicePin1PullUp[event->TaskIndex]) ? INPUT_PULLUP : INPUT); 108 | setPinState(PLUGIN_ID_143, pin, PIN_MODE_INPUT, 0); 109 | } 110 | log += pin; 111 | log += F(" "); 112 | } 113 | addLog(LOG_LEVEL_INFO, log); 114 | 115 | success = true; 116 | break; 117 | } 118 | 119 | case PLUGIN_READ: 120 | { 121 | UserVar[event->BaseVarIndex + 0] = (Plugin_143_millisPresenceEnd > 0); 122 | success = true; 123 | break; 124 | } 125 | 126 | case PLUGIN_FIFTY_PER_SECOND: 127 | //case PLUGIN_TEN_PER_SECOND: 128 | { 129 | boolean presence = false; 130 | boolean send = false; 131 | byte value; 132 | 133 | for (byte i=0; i<3; i++) 134 | if (Plugin_143_pin[i] >= 0) 135 | { 136 | value = digitalRead(Plugin_143_pin[i]); 137 | if (Plugin_143_lowActive) 138 | value = !value; 139 | 140 | if (value) 141 | { 142 | if (Plugin_143_counter[i] <= 5) 143 | Plugin_143_counter[i]++; 144 | //test Serial.printf("."); 145 | } 146 | else 147 | Plugin_143_counter[i] = 0; 148 | 149 | if (Plugin_143_counter[i] > 5) 150 | presence = true; 151 | } 152 | 153 | if (Plugin_143_useAin) 154 | { 155 | static float filter0 = 0; 156 | static float filter1 = 0; 157 | 158 | float ain = analogRead(A0) / 1023.0; 159 | 160 | filter0 = 0.95 * filter0 + 0.05 * ain; 161 | filter1 = 0.90 * filter1 + 0.10 * ain; 162 | float diff = (filter0 - filter1) * 20.0; 163 | if (diff < 0) 164 | diff = -diff; 165 | 166 | if (diff > 1.0) 167 | presence = true; 168 | } 169 | 170 | if (presence) // anyone here now? 171 | { 172 | if (Plugin_143_millisPresenceEnd == 0) // nobody present? 173 | { 174 | send = true; 175 | } 176 | Plugin_143_millisPresenceEnd = millis() + Plugin_143_millisPresenceTime; 177 | } 178 | else // nobody here now? 179 | { 180 | if (Plugin_143_millisPresenceEnd != 0 && Plugin_143_millisPresenceEnd < millis()) // timeout? 181 | { 182 | send = true; 183 | Plugin_143_millisPresenceEnd = 0; 184 | } 185 | } 186 | 187 | if (send) 188 | { 189 | UserVar[event->BaseVarIndex] = presence; 190 | event->sensorType = SENSOR_TYPE_SWITCH; 191 | 192 | String log = F("Any1 : Presence="); 193 | log += presence; 194 | addLog(LOG_LEVEL_INFO, log); 195 | 196 | sendData(event); 197 | } 198 | 199 | success = true; 200 | break; 201 | } 202 | 203 | } 204 | return success; 205 | } 206 | 207 | #endif 208 | -------------------------------------------------------------------------------- /_P144_RC-Switch-TX.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 144: RC-Switch TX ######################################### 3 | //####################################################################################################### 4 | // written by Jochen Krapf (jk@nerd2nerd.org) 5 | 6 | // List of commands: 7 | // (1) RC, 8 | // (2) RC,,, 9 | 10 | // List of RC params: 11 | // (a) SEND= 12 | // Send binary code with any length ("RC,SEND=000000000001010100010001") 13 | // (b) SEND= 14 | // Send tristate code with any length ("RC,SEND=00000FFF0F0F") 15 | // (c) SENDDEC= 16 | // Send 24 bit decimal code ("RC,SENDDEC=5393") 17 | // (d) ON= 18 | // Send binary code for simple 10 DIP switch devices ("RC,ON=1010100010") 19 | // (e) ON=<1..4><1..4> 20 | // Send switch position for simple 2 rotary switch devices ("RC,ON=42") 21 | // (f) ON=<1..4><1..4> 22 | // Send switch position for Intertechno devices ("RC,ON=a42") 23 | // (f) OFF= as ON... 24 | // (g) PROTOCOL= 25 | // Set protocoln for devices ("RC,PROTOCOL=2") default=1 26 | // (h) PULSE= 27 | // Set pulse length ("RC,PULSE=320") default=320 28 | // (i) REPEAT= 29 | // Set number of transmission repeats ("RC,REPEAT=15") default=? 30 | // 31 | // Combinations: 32 | // e.g. "RC,PROTOCOL=2,PULSE=320,REPEAT=15,SEND=000000000001010100010001" 33 | 34 | 35 | #include //https://github.com/sui77/rc-switch.git 36 | 37 | static RCSwitch Plugin_144_RC = RCSwitch(); 38 | 39 | #define PLUGIN_144 40 | #define PLUGIN_ID_144 144 41 | #define PLUGIN_NAME_144 "RC-Switch TX" 42 | 43 | 44 | boolean Plugin_144(byte function, struct EventStruct *event, String& string) 45 | { 46 | boolean success = false; 47 | 48 | switch (function) 49 | { 50 | case PLUGIN_DEVICE_ADD: 51 | { 52 | Device[++deviceCount].Number = PLUGIN_ID_144; 53 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 54 | Device[deviceCount].Ports = 0; 55 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 56 | Device[deviceCount].PullUpOption = false; 57 | Device[deviceCount].InverseLogicOption = false; 58 | Device[deviceCount].FormulaOption = false; 59 | Device[deviceCount].ValueCount = 0; 60 | Device[deviceCount].SendDataOption = false; 61 | Device[deviceCount].TimerOption = false; 62 | Device[deviceCount].TimerOptional = false; 63 | Device[deviceCount].GlobalSyncOption = true; 64 | break; 65 | } 66 | 67 | case PLUGIN_GET_DEVICENAME: 68 | { 69 | string = F(PLUGIN_NAME_144); 70 | break; 71 | } 72 | 73 | case PLUGIN_WEBFORM_LOAD: 74 | { 75 | success = true; 76 | break; 77 | } 78 | 79 | case PLUGIN_WEBFORM_SAVE: 80 | { 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_INIT: 86 | { 87 | int pin = Settings.TaskDevicePin1[event->TaskIndex]; 88 | if (pin >= 0) 89 | { 90 | String log = F("RC-Sw: Pin "); 91 | log += pin; 92 | log += F(" "); 93 | 94 | Plugin_144_RC.enableTransmit(pin); 95 | 96 | addLog(LOG_LEVEL_INFO, log); 97 | } 98 | 99 | 100 | if (Settings.TaskDevicePin1[event->TaskIndex] >= 0) 101 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 102 | if (Settings.TaskDevicePin2[event->TaskIndex] >= 0) 103 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], OUTPUT); 104 | if (Settings.TaskDevicePin3[event->TaskIndex] >= 0) 105 | pinMode(Settings.TaskDevicePin3[event->TaskIndex], OUTPUT); 106 | 107 | for (byte i=0; i<3; i++) 108 | if (Settings.TaskDevicePin[i][event->TaskIndex] >= 0) 109 | pinMode(Settings.TaskDevicePin[i][event->TaskIndex], OUTPUT); 110 | 111 | success = true; 112 | break; 113 | } 114 | 115 | case PLUGIN_WRITE: 116 | { 117 | String command = parseString(string, 1); 118 | 119 | if (command == F("rc")) 120 | { 121 | String param; 122 | byte paramIdx = 2; 123 | 124 | string.replace(" ", " "); 125 | string.replace(" =", "="); 126 | string.replace("= ", "="); 127 | 128 | param = parseString(string, paramIdx++); 129 | while (param.length()) 130 | { 131 | addLog(LOG_LEVEL_DEBUG_MORE, param); 132 | 133 | int index = param.indexOf('='); 134 | if (index > 0) 135 | { 136 | String paramKey = param.substring(0, index); 137 | String paramVal = param.substring(index+1); 138 | paramKey.toUpperCase(); 139 | 140 | addLog(LOG_LEVEL_DEBUG_MORE, paramKey); 141 | addLog(LOG_LEVEL_DEBUG_MORE, paramVal); 142 | 143 | if (paramKey == F("SEND")) 144 | { 145 | if (paramVal.indexOf("F") >= 0) 146 | Plugin_144_RC.sendTriState(&(paramVal[0])); 147 | else 148 | Plugin_144_RC.send(&(paramVal[0])); 149 | } 150 | if (paramKey == F("SENDDEC")) 151 | { 152 | Plugin_144_RC.send(paramVal.toInt(), 24); 153 | } 154 | if (paramKey == F("ON")) 155 | { 156 | if (paramVal.length()==10) //simple 10 DIP switch 157 | Plugin_144_RC.switchOn(&(paramVal.substring(0, 5)[0]), &(paramVal.substring(5)[0])); 158 | else if (paramVal.length()==2) //2x rotary switch 1..4 159 | Plugin_144_RC.switchOn(paramVal[0]-'0', paramVal[1]-'0'); 160 | else if (paramVal.length()==3) //Intertechno outlets 161 | Plugin_144_RC.switchOn(paramVal[0], paramVal[1]-'0', paramVal[2]-'0'); 162 | } 163 | if (paramKey == F("OFF")) 164 | { 165 | if (paramVal.length()==10) //simple 10 DIP switch 166 | Plugin_144_RC.switchOff(&(paramVal.substring(0, 5)[0]), &(paramVal.substring(5)[0])); 167 | else if (paramVal.length()==2) //2x rotary switch 1..4 168 | Plugin_144_RC.switchOff(paramVal[0]-'0', paramVal[1]-'0'); 169 | else if (paramVal.length()==3) //Intertechno outlets 170 | Plugin_144_RC.switchOn(paramVal[0], paramVal[1]-'0', paramVal[2]-'0'); 171 | } 172 | if (paramKey == F("PROTOCOL")) 173 | { 174 | Plugin_144_RC.setProtocol(paramVal.toInt()); 175 | } 176 | if (paramKey == F("PULSE")) 177 | { 178 | Plugin_144_RC.setPulseLength(paramVal.toInt()); 179 | } 180 | if (paramKey == F("REPEAT")) 181 | { 182 | Plugin_144_RC.setRepeatTransmit(paramVal.toInt()); 183 | } 184 | } 185 | 186 | param = parseString(string, paramIdx++); 187 | } 188 | 189 | success = true; 190 | } 191 | 192 | break; 193 | } 194 | 195 | case PLUGIN_READ: 196 | { 197 | //no values 198 | success = true; 199 | break; 200 | } 201 | 202 | } 203 | return success; 204 | } 205 | -------------------------------------------------------------------------------- /_P149_MHZ19.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * This plug in is written by Dmitry (rel22 ___ inbox.ru) 4 | * Plugin is based upon SenseAir plugin by Daniel Tedenljung info__AT__tedenljungconsulting.com 5 | * 6 | * This plugin reads the CO2 and Temperateure values from MH-Z19 NDIR Sensor 7 | * DevicePin1 - is RX for ESP 8 | * DevicePin2 - is TX for ESP 9 | */ 10 | 11 | 12 | #define PLUGIN_149 13 | #define PLUGIN_ID_149 149 14 | #define PLUGIN_NAME_149 "CO2 Sensor - MH-Z19" 15 | #define PLUGIN_VALUENAME1_149 "PPM" 16 | #define PLUGIN_VALUENAME2_149 "Temperature" 17 | #define PLUGIN_READ_TIMEOUT 3000 18 | 19 | #include 20 | SoftwareSerial * Plugin_149_S8; 21 | unsigned long Plugin_149_start; 22 | boolean Plugin_149_init = false; 23 | const int Plugin_149_warmUpTime = 180000; // 3 minutes in ms 24 | 25 | // 9-bytes CMD PPM read command 26 | byte mhzCmd[9] = { 0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 }; 27 | byte mhzResp[9]; // 9 bytes bytes response 28 | 29 | boolean Plugin_149(byte function, struct EventStruct * event, String& string) 30 | { 31 | bool success = false; 32 | 33 | switch (function) 34 | { 35 | case PLUGIN_DEVICE_ADD: 36 | { 37 | Device[++deviceCount].Number = PLUGIN_ID_149; 38 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 39 | Device[deviceCount].VType = SENSOR_TYPE_DUAL; 40 | Device[deviceCount].Ports = 0; 41 | Device[deviceCount].PullUpOption = false; 42 | Device[deviceCount].InverseLogicOption = false; 43 | Device[deviceCount].FormulaOption = true; 44 | Device[deviceCount].ValueCount = 2; 45 | Device[deviceCount].SendDataOption = true; 46 | Device[deviceCount].TimerOption = true; 47 | Device[deviceCount].GlobalSyncOption = true; 48 | break; 49 | } 50 | 51 | case PLUGIN_GET_DEVICENAME: 52 | { 53 | string = F(PLUGIN_NAME_149); 54 | break; 55 | } 56 | 57 | case PLUGIN_GET_DEVICEVALUENAMES: 58 | { 59 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_149)); 60 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_149)); 61 | break; 62 | } 63 | 64 | case PLUGIN_WEBFORM_LOAD: 65 | { 66 | addFormNote(string, F("1st GPIO connects to sensor TX pin. 2nd GPIO connects to sensor RX pin.")); 67 | success = true; 68 | break; 69 | } 70 | 71 | case PLUGIN_INIT: 72 | { 73 | if (Settings.TaskDevicePin1[event->TaskIndex] != -1 && Settings.TaskDevicePin2[event->TaskIndex] != -1) 74 | { 75 | Plugin_149_S8 = new SoftwareSerial(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex]); 76 | Plugin_149_S8->begin(9600); 77 | Plugin_149_start = millis(); 78 | Plugin_149_init = false; // force warmup period 79 | String log = F("MHZ19: Init OK "); 80 | addLog(LOG_LEVEL_INFO, log); 81 | } 82 | 83 | success = true; 84 | break; 85 | } 86 | 87 | case PLUGIN_READ: 88 | { 89 | if (Plugin_149_init) 90 | { 91 | // send read PPM command 92 | int nbBytesSent = Plugin_149_S8->write(mhzCmd, 9); 93 | if (nbBytesSent != 9) 94 | { 95 | String log = F("MHZ19: Error, nb bytes sent != 9 : "); 96 | log += nbBytesSent; 97 | addLog(LOG_LEVEL_INFO, log); 98 | } 99 | 100 | // get response 101 | memset(mhzResp, 0, 9); 102 | 103 | long start = millis(); 104 | int counter = 0; 105 | while (((millis() - start) < PLUGIN_READ_TIMEOUT) && (counter < 9)) 106 | { 107 | if (Plugin_149_S8->available() > 0) 108 | { 109 | mhzResp[counter++] = Plugin_149_S8->read(); 110 | } 111 | else 112 | { 113 | delay(10); 114 | } 115 | } 116 | 117 | if (counter < 9) 118 | { 119 | String log = F("MHZ19: Error, timeout while trying to read"); 120 | addLog(LOG_LEVEL_INFO, log); 121 | } 122 | 123 | unsigned int ppm = 0; 124 | int temperature = 0; 125 | int i; 126 | byte crc = 0; 127 | for (i = 1; i < 8; i++) crc += mhzResp[i]; 128 | 129 | crc = 255 - crc; 130 | crc++; 131 | 132 | if (!(mhzResp[0] == 0xFF && mhzResp[1] == 0x86 && mhzResp[8] == crc) ) 133 | { 134 | String log = F("MHZ19: Read error : CRC = "); 135 | log += String(crc); 136 | log += " / "; 137 | log += String(mhzResp[8]); 138 | log += " bytes read => "; 139 | for (i = 0; i < 9; i++) 140 | { 141 | log += mhzResp[i]; 142 | log += "/"; 143 | } 144 | 145 | addLog(LOG_LEVEL_ERROR, log); 146 | 147 | success = false; 148 | break; 149 | } 150 | else 151 | { 152 | // calculate CO2 PPM 153 | unsigned int mhzRespHigh = (unsigned int) mhzResp[2]; 154 | unsigned int mhzRespLow = (unsigned int) mhzResp[3]; 155 | ppm = (256 * mhzRespHigh) + mhzRespLow; 156 | temperature = (unsigned int) mhzResp[4] - 40; 157 | } 158 | 159 | UserVar[event->BaseVarIndex] = (float) ppm; 160 | UserVar[event->BaseVarIndex + 1] = temperature; 161 | String log = F("MHZ19: PPM value: "); 162 | log += ppm; 163 | addLog(LOG_LEVEL_INFO, log); 164 | log = F("MH-Z19: Temperature: "); 165 | log += temperature; 166 | addLog(LOG_LEVEL_INFO, log); 167 | success = true; 168 | break; 169 | } 170 | else if (millis() - Plugin_149_start >= Plugin_149_warmUpTime) 171 | { 172 | Plugin_149_init = true; 173 | String log = F("MH-Z19 : Warmup Complete"); 174 | addLog(LOG_LEVEL_DEBUG, log); 175 | } 176 | else 177 | { 178 | // wait for warmup 179 | String log = F("MH-Z19 : warming up (seconds) : "); 180 | log += ((millis() - Plugin_149_start) / 1000); 181 | log += F(" of "); 182 | log += Plugin_149_warmUpTime/1000; 183 | addLog(LOG_LEVEL_DEBUG, log); 184 | } 185 | break; 186 | } 187 | } 188 | 189 | return success; 190 | } // Plugin_149 191 | -------------------------------------------------------------------------------- /_P150_SDM120C.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //############################# Plugin 150: SDM120C Eastron Energy Meter ################################ 3 | //####################################################################################################### 4 | /* 5 | Plugin written by: Sergio Faustino sjfaustino__AT__gmail.com 6 | 7 | This plugin reads available values of an Eastron SDM120C Energy Meter. 8 | It will also work with all the other superior model such as SDM220 AND SDM630 series. 9 | */ 10 | 11 | #ifdef PLUGIN_BUILD_DEV 12 | 13 | #define PLUGIN_150 14 | #define PLUGIN_ID_150 150 15 | #define PLUGIN_NAME_150 "Energy (AC) - Eastron SDM120C" 16 | #define PLUGIN_VALUENAME1_150 "Voltage" 17 | 18 | boolean Plugin_150_init = false; 19 | 20 | #include // Requires SDM library from Reaper7 - https://github.com/reaper7/SDM_Energy_Meter/ 21 | SDM<2400, D6, D7> Plugin_150_SDM; 22 | 23 | boolean Plugin_150(byte function, struct EventStruct *event, String& string) 24 | { 25 | boolean success = false; 26 | 27 | switch (function) 28 | { 29 | 30 | case PLUGIN_DEVICE_ADD: 31 | { 32 | Device[++deviceCount].Number = PLUGIN_ID_150; 33 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; // connected through 2 datapins 34 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 35 | Device[deviceCount].Ports = 0; 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 | Device[deviceCount].TimerOption = true; 42 | Device[deviceCount].GlobalSyncOption = true; 43 | break; 44 | } 45 | 46 | case PLUGIN_GET_DEVICENAME: 47 | { 48 | string = F(PLUGIN_NAME_150); 49 | break; 50 | } 51 | 52 | case PLUGIN_GET_DEVICEVALUENAMES: 53 | { 54 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_150)); 55 | break; 56 | } 57 | 58 | case PLUGIN_WEBFORM_LOAD: 59 | { 60 | byte meter_model = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 61 | byte meter_baudrate = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 62 | byte query = Settings.TaskDevicePluginConfig[event->TaskIndex][3]; 63 | 64 | String options_model[3] = { F("SDM120C"), F("SDM220T"), F("SDM630") }; 65 | addFormSelector(string, F("Model Type"), F("plugin_150_meter_model"), 3, options_model, NULL, meter_model ); 66 | 67 | String options_baudrate[6] = { F("1200"), F("2400"), F("4800"), F("9600"), F("19200"), F("38400") }; 68 | addFormSelector(string, F("Baud Rate"), F("plugin_150_meter_baudrate"), 6, options_baudrate, NULL, meter_baudrate ); 69 | 70 | if (meter_model == 0 && meter_baudrate > 3) 71 | string += F(" SDM120 only allows up to 9600 baud with default 2400!"); 72 | 73 | if (meter_model == 2 && meter_baudrate == 0) 74 | string += F(" SDM630 only allows 2400 to 38400 baud with default 9600!"); 75 | 76 | String options_query[10] = { F("Voltage (V)"), 77 | F("Current (A)"), 78 | F("Power (W)"), 79 | F("Active Apparent Power (VA)"), 80 | F("Reactive Apparent Power (VAr)"), 81 | F("Power Factor (cfi?)"), 82 | F("Frequency (Hz)"), 83 | F("Import Active Energy (Wh)"), 84 | F("Export Active Energy (Wh)"), 85 | F("Total Active Energy (Wh)") }; 86 | addFormSelector(string, F("Query"), F("plugin_150_query"), 10, options_query, NULL, query ); 87 | 88 | success = true; 89 | break; 90 | } 91 | 92 | case PLUGIN_WEBFORM_SAVE: 93 | { 94 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_150")); 95 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_150_meter_model")); 96 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_150_meter_baudrate")); 97 | Settings.TaskDevicePluginConfig[event->TaskIndex][3] = getFormItemInt(F("plugin_150_query")); 98 | 99 | Plugin_150_init = false; // Force device setup next time 100 | success = true; 101 | break; 102 | } 103 | 104 | case PLUGIN_INIT: 105 | { 106 | Plugin_150_init = true; 107 | 108 | // SDM<2400, Settings.TaskDevicePin1[event->TaskIndex], 109 | // Settings.TaskDevicePin2[event->TaskIndex]> Plugin_150_SDM; 110 | Plugin_150_SDM.begin(); 111 | success = true; 112 | break; 113 | } 114 | 115 | case PLUGIN_READ: 116 | { 117 | 118 | if (Plugin_150_init) 119 | { 120 | float _tempvar = 0; 121 | String log = F("EASTRON: "); 122 | switch(Settings.TaskDevicePluginConfig[event->TaskIndex][3]) 123 | { 124 | case 0: 125 | { 126 | _tempvar = Plugin_150_SDM.readVal(SDM120C_VOLTAGE); 127 | log += F("Voltage "); 128 | break; 129 | } 130 | case 1: 131 | { 132 | _tempvar = Plugin_150_SDM.readVal(SDM120C_CURRENT); 133 | log += F("Current "); 134 | break; 135 | } 136 | case 2: 137 | { 138 | _tempvar = Plugin_150_SDM.readVal(SDM120C_POWER); 139 | log += F("Power "); 140 | break; 141 | } 142 | case 3: 143 | { 144 | _tempvar = Plugin_150_SDM.readVal(SDM120C_ACTIVE_APPARENT_POWER); 145 | log += F("Active Apparent Power "); 146 | break; 147 | } 148 | case 4: 149 | { 150 | _tempvar = Plugin_150_SDM.readVal(SDM120C_REACTIVE_APPARENT_POWER); 151 | log += F("Reactive Apparent Power "); 152 | break; 153 | } 154 | case 5: 155 | { 156 | _tempvar = Plugin_150_SDM.readVal(SDM120C_POWER_FACTOR); 157 | log += F("Power Factor "); 158 | break; 159 | } 160 | case 6: 161 | { 162 | _tempvar = Plugin_150_SDM.readVal(SDM120C_FREQUENCY); 163 | log += F("Frequency "); 164 | break; 165 | } 166 | case 7: 167 | { 168 | _tempvar = Plugin_150_SDM.readVal(SDM120C_IMPORT_ACTIVE_ENERGY); 169 | log += F("Import Active Energy "); 170 | break; 171 | } 172 | case 8: 173 | { 174 | _tempvar = Plugin_150_SDM.readVal(SDM120C_EXPORT_ACTIVE_ENERGY); 175 | log += F("Export Active Energy "); 176 | break; 177 | } 178 | case 9: 179 | { 180 | _tempvar = Plugin_150_SDM.readVal(SDM120C_TOTAL_ACTIVE_ENERGY); 181 | log += F("Total Active Energy "); 182 | break; 183 | } 184 | } 185 | 186 | UserVar[event->BaseVarIndex] = _tempvar; 187 | log += _tempvar; 188 | addLog(LOG_LEVEL_INFO, log); 189 | 190 | success = true; 191 | break; 192 | } 193 | break; 194 | } 195 | } 196 | return success; 197 | } 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /_P152_MCP42010.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 152: MCP42010 ############################################# 3 | //################################## I use GPIO 12 / 14 / 15 ############################################ 4 | //####################################################################################################### 5 | // written by antibill 6 | 7 | // Usage: 8 | // (1): Set value to potentiometer (http://xx.xx.xx.xx/control?cmd=digipot,0,255) 9 | // (2): Set value to potentiometer (http://xx.xx.xx.xx/control?cmd=digipot,1,0) 10 | 11 | #include 12 | // https://github.com/mensink/arduino-lib-MCP42010 13 | static float Plugin_152_PotDest[2] = {0,0}; 14 | 15 | #define PLUGIN_152 16 | #define PLUGIN_ID_152 152 17 | #define PLUGIN_NAME_152 "MCP42010" 18 | #define PLUGIN_VALUENAME1_152 "DigiPot0" 19 | #define PLUGIN_VALUENAME2_152 "DigiPot1" 20 | 21 | int Plugin_152_pin[3] = {-1,-1,-1}; 22 | 23 | 24 | 25 | boolean Plugin_152(byte function, struct EventStruct *event, String& string) 26 | { 27 | boolean success = false; 28 | 29 | switch (function) 30 | { 31 | case PLUGIN_DEVICE_ADD: 32 | { 33 | Device[++deviceCount].Number = PLUGIN_ID_152; 34 | Device[deviceCount].Type = DEVICE_TYPE_DUMMY; // SPI pins for ESP8266 are CS=15, CLK=14, MOSI=13 35 | Device[deviceCount].Ports = 0; 36 | Device[deviceCount].VType = SENSOR_TYPE_DUAL; 37 | Device[deviceCount].PullUpOption = false; 38 | Device[deviceCount].InverseLogicOption = false; 39 | Device[deviceCount].FormulaOption = true; 40 | Device[deviceCount].ValueCount = 2; 41 | Device[deviceCount].SendDataOption = true; 42 | Device[deviceCount].TimerOption = true; 43 | Device[deviceCount].TimerOptional = true; 44 | Device[deviceCount].GlobalSyncOption = true; 45 | break; 46 | } 47 | 48 | case PLUGIN_GET_DEVICENAME: 49 | { 50 | string = F(PLUGIN_NAME_152); 51 | break; 52 | } 53 | 54 | case PLUGIN_GET_DEVICEVALUENAMES: 55 | { 56 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_152)); 57 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_152)); 58 | break; 59 | } 60 | 61 | case PLUGIN_WEBFORM_LOAD: 62 | { 63 | // char tmpString[128]; 64 | 65 | addHtml(F("GPIO:")); 66 | 67 | addHtml(F("1st GPIO (CS):")); 68 | addPinSelect(false, "taskdevicepin1", Plugin_152_pin[0] = Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 69 | addHtml(F("2nd GPIO (CLK):")); 70 | addPinSelect(false, "taskdevicepin2", Plugin_152_pin[1] = Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 71 | addHtml(F("3rd GPIO (MOSI):")); 72 | addPinSelect(false, "taskdevicepin3", Plugin_152_pin[2] = Settings.TaskDevicePluginConfig[event->TaskIndex][2]); 73 | 74 | success = true; 75 | break; 76 | } 77 | 78 | case PLUGIN_WEBFORM_SAVE: 79 | { 80 | 81 | 82 | String plugin2 = WebServer.arg("taskdevicepin1"); 83 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin2.toInt(); 84 | String plugin3 = WebServer.arg("taskdevicepin2"); 85 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin3.toInt(); 86 | String plugin4 = WebServer.arg("taskdevicepin3"); 87 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin4.toInt(); 88 | 89 | success = true; 90 | break; 91 | } 92 | 93 | case PLUGIN_INIT: 94 | { 95 | int pCS = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 96 | int pCLK = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 97 | int pMOSI = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 98 | Plugin_152_pin[0] = pCS; 99 | Plugin_152_pin[1] = pCLK; 100 | Plugin_152_pin[2] = pMOSI; 101 | 102 | success = true; 103 | break; 104 | } 105 | 106 | case PLUGIN_WRITE: 107 | { 108 | 109 | String tmpString = string; 110 | int argIndex = tmpString.indexOf(','); 111 | if (argIndex) 112 | tmpString = tmpString.substring(0, argIndex); 113 | 114 | if (tmpString.equalsIgnoreCase(F("digipot"))) 115 | { 116 | int pot; 117 | int value; 118 | pot = event->Par1; 119 | value = event->Par2; 120 | 121 | MCP42010 digipot(Plugin_152_pin[0], Plugin_152_pin[1], Plugin_152_pin[2]); 122 | Plugin_152_PotDest[pot] = value; 123 | digipot.setPot(pot,value); 124 | success = true; 125 | } 126 | 127 | 128 | break; 129 | } 130 | 131 | case PLUGIN_READ: 132 | { 133 | 134 | UserVar[event->BaseVarIndex + 0]= Plugin_152_PotDest[0] ; 135 | UserVar[event->BaseVarIndex + 1] = Plugin_152_PotDest[1] ; 136 | success = true; 137 | break; 138 | } 139 | 140 | 141 | } 142 | return success; 143 | } 144 | -------------------------------------------------------------------------------- /_P153_MAX44009.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //############################### Plugin 153: MAX44009 I2C 0x4A ####################################### 3 | //####################################################################################################### 4 | 5 | // based on : 6 | // 1) https://github.com/RobTillaart/Arduino/tree/master/libraries/Max44009 7 | // 2) https://github.com/dantudose/MAX44009/blob/master/MAX44009.cpp 8 | // 9 | // written by https://github.com/apszowski 10 | 11 | #ifdef PLUGIN_BUILD_TESTING 12 | 13 | #define PLUGIN_153 14 | #define PLUGIN_ID_153 153 15 | #define PLUGIN_NAME_153 "Light/Lux - MAX44009 (GY-49)" 16 | #define PLUGIN_VALUENAME1_153 "Lux" 17 | 18 | boolean Plugin_153_init = false; 19 | 20 | enum { 21 | //I2C address 22 | MAX44009_I2C_ADDR = 0x4A, 23 | // CONFIGURATION 24 | MAX44009_REGISTER_CONFIGURATION = 0x02, 25 | MAX44009_CFG_MANUAL = 0x40, 26 | MAX44009_CFG_CONTINUOUS = 0x80, 27 | //LUX READING 28 | MAX44009_REGISTER_LUX_HIGH = 0x03, 29 | MAX44009_REGISTER_LUX_LOW = 0x04, 30 | }; 31 | 32 | 33 | uint16_t Plugin_153_readRegister(uint8_t reg) { 34 | uint16_t ret; 35 | Wire.beginTransmission(MAX44009_I2C_ADDR); 36 | Wire.write(reg); 37 | Wire.endTransmission(); 38 | Wire.requestFrom(MAX44009_I2C_ADDR,1); 39 | ret = Wire.read(); 40 | return ret; 41 | } 42 | 43 | void Plugin_153_writeRegister(uint8_t reg, uint8_t value){ 44 | Wire.beginTransmission(MAX44009_I2C_ADDR); 45 | Wire.write(reg); 46 | Wire.write(value); 47 | Wire.endTransmission(); 48 | } 49 | 50 | float Plugin_153_readLux(void) 51 | { 52 | uint8_t luxHigh = Plugin_153_readRegister(MAX44009_REGISTER_LUX_HIGH); 53 | uint8_t luxLow = Plugin_153_readRegister(MAX44009_REGISTER_LUX_LOW); 54 | uint8_t e = (luxHigh & 0xF0) >> 4; 55 | uint8_t m = (luxHigh & 0x0F) << 4 | luxLow; 56 | float lux = pow(2,e) * m * 0.045; 57 | return lux; 58 | } 59 | void Plugin_153_setModeAutomatic(void) 60 | { 61 | uint8_t config = Plugin_153_readRegister(MAX44009_REGISTER_CONFIGURATION); 62 | config &= ~MAX44009_CFG_CONTINUOUS; // off 63 | config &= ~MAX44009_CFG_MANUAL; // off 64 | Plugin_153_writeRegister(MAX44009_REGISTER_CONFIGURATION, config); 65 | } 66 | 67 | void Plugin_153_setModeContinuous(void) 68 | { 69 | uint8_t config = Plugin_153_readRegister(MAX44009_REGISTER_CONFIGURATION); 70 | config |= MAX44009_CFG_CONTINUOUS; // on 71 | config &= ~MAX44009_CFG_MANUAL; // off 72 | Plugin_153_writeRegister(MAX44009_REGISTER_CONFIGURATION, config); 73 | } 74 | 75 | void Plugin_153_setModeManual(uint8_t CDR, uint8_t TIM) 76 | { 77 | uint8_t config = Plugin_153_readRegister(MAX44009_REGISTER_CONFIGURATION); 78 | config &= ~MAX44009_CFG_CONTINUOUS; // off 79 | config |= MAX44009_CFG_MANUAL; // on 80 | config &= 0xF0; // clear CDR & TIM bits 81 | config |= CDR << 3 | TIM; 82 | Plugin_153_writeRegister(MAX44009_REGISTER_CONFIGURATION, config); 83 | } 84 | 85 | boolean Plugin_153(byte function, struct EventStruct *event, String& string) 86 | { 87 | boolean success = false; 88 | switch (function) 89 | { 90 | case PLUGIN_DEVICE_ADD: 91 | { 92 | Device[++deviceCount].Number = PLUGIN_ID_153; 93 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 94 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 95 | Device[deviceCount].Ports = 0; 96 | Device[deviceCount].PullUpOption = false; 97 | Device[deviceCount].InverseLogicOption = false; 98 | Device[deviceCount].FormulaOption = true; 99 | Device[deviceCount].SendDataOption = true; 100 | Device[deviceCount].ValueCount = 1; 101 | Device[deviceCount].TimerOption = true; 102 | Device[deviceCount].GlobalSyncOption = true; 103 | break; 104 | } 105 | 106 | case PLUGIN_GET_DEVICENAME: 107 | { 108 | string = F(PLUGIN_NAME_153); 109 | break; 110 | } 111 | 112 | case PLUGIN_GET_DEVICEVALUENAMES: 113 | { 114 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_153)); 115 | break; 116 | } 117 | 118 | case PLUGIN_WEBFORM_LOAD: 119 | { 120 | byte choice_mode = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 121 | String options[8]; 122 | int optionValues[8]; 123 | options[0] = F("Automatic"); 124 | optionValues[0] = 0; 125 | options[1] = F("Continuous"); 126 | optionValues[1] = 1; 127 | options[2] = F("Manual"); 128 | optionValues[2] = 2; 129 | addFormSelector(string, F("Mode"), F("plugin_153_mode"), 3, options, optionValues, choice_mode); 130 | if( choice_mode != 0) 131 | { 132 | //######################## 133 | byte choice_division = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 134 | options[0] = F("Not divided"); 135 | optionValues[0] = 0; 136 | options[1] = F("Divided 1/8"); 137 | optionValues[1] = 1; 138 | addFormSelector(string, F("Current Division Ratio"), F("plugin_153_divide"), 2, options, optionValues, choice_division); 139 | //######################## 140 | byte choice_time = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 141 | float integration_time = 800; 142 | for( uint8_t i = 0 ; i <= 7 ; i++) 143 | { 144 | options[i] = integration_time; 145 | options[i] += F(" ms"); 146 | optionValues[i] = i; 147 | integration_time = integration_time/2.0; 148 | } 149 | addFormSelector(string, F("Integration Time"), F("plugin_153_time"), 8, options, optionValues, choice_time); 150 | } 151 | success = true; 152 | break; 153 | } 154 | 155 | case PLUGIN_WEBFORM_SAVE: 156 | { 157 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_153_mode")); 158 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("plugin_153_divide")); 159 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = getFormItemInt(F("plugin_153_time")); 160 | Plugin_153_init = false; 161 | success = true; 162 | break; 163 | } 164 | 165 | case PLUGIN_INIT: 166 | { 167 | Plugin_153_init = true; 168 | uint8_t mode = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 169 | uint8_t divide = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 170 | uint8_t tim = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 171 | 172 | String log = F("MAX44009 :\rINIT MODE = "); 173 | if( mode == 0) 174 | { 175 | Plugin_153_setModeAutomatic(); 176 | log += F("Automatic"); 177 | } 178 | else if ( mode == 1) 179 | { 180 | Plugin_153_setModeContinuous(); 181 | log += F("Continuous"); 182 | } 183 | else 184 | { 185 | Plugin_153_setModeManual(divide,tim); 186 | log += F("Manual , CDR = "); 187 | log += divide; 188 | log += F(", Integration Time = "); 189 | log += tim; 190 | } 191 | addLog(LOG_LEVEL_INFO,log); 192 | success = true; 193 | break; 194 | } 195 | 196 | case PLUGIN_READ: 197 | { 198 | UserVar[event->BaseVarIndex] = (float) Plugin_153_readLux(); 199 | String log = F("MAX44009 : Ambient Light: "); 200 | log += UserVar[event->BaseVarIndex]; 201 | addLog(LOG_LEVEL_INFO,log); 202 | success = true; 203 | break; 204 | } 205 | } 206 | return success; 207 | } 208 | 209 | #endif 210 | -------------------------------------------------------------------------------- /_P171_PZEM-004T.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################### Plugin 171 PZEM-004T AC Current and Voltage measurement sensor #################### 3 | //####################################################################################################### 4 | // 5 | // This plugin is interfacing with PZEM-004T Sesor with softserial communication as the sensor 6 | // has an UART pinout (TX/RX/VCC/GND) 7 | // 8 | 9 | //#ifdef PLUGIN_BUILD_TESTING 10 | 11 | #include 12 | #include 13 | PZEM004T *Plugin_171_pzem; 14 | IPAddress pzemIP(192,168,1,1); // required by the library but not used (dummy value) 15 | 16 | #define PLUGIN_171 17 | #define PLUGIN_ID_171 171 18 | #define PLUGIN_171_DEBUG false //activate extra log info in the debug 19 | #define PLUGIN_NAME_171 "Voltage & Current (AC) - PZEM-004T [TESTING]" 20 | #define PLUGIN_VALUENAME1_171 "Voltage (V)" 21 | #define PLUGIN_VALUENAME2_171 "Current (A)" 22 | #define PLUGIN_VALUENAME3_171 "Power (W)" 23 | #define PLUGIN_VALUENAME4_171 "Energy (Wh)" 24 | 25 | // local parameter for this plugin 26 | #define PZEM_MAX_ATTEMPT 3 27 | 28 | boolean Plugin_171(byte function, struct EventStruct *event, String& string) 29 | { 30 | boolean success = false; 31 | 32 | switch (function) 33 | { 34 | case PLUGIN_DEVICE_ADD: 35 | { 36 | Device[++deviceCount].Number = PLUGIN_ID_171; 37 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 38 | Device[deviceCount].VType = SENSOR_TYPE_QUAD; 39 | Device[deviceCount].Ports = 0; 40 | Device[deviceCount].PullUpOption = false; 41 | Device[deviceCount].InverseLogicOption = false; 42 | Device[deviceCount].FormulaOption = true; 43 | Device[deviceCount].ValueCount = 4; 44 | Device[deviceCount].SendDataOption = true; 45 | Device[deviceCount].TimerOption = true; 46 | Device[deviceCount].GlobalSyncOption = false; 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICENAME: 51 | { 52 | string = F(PLUGIN_NAME_171); 53 | break; 54 | } 55 | 56 | case PLUGIN_GET_DEVICEVALUENAMES: 57 | { 58 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_171)); 59 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_171)); 60 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_171)); 61 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_171)); 62 | break; 63 | } 64 | 65 | case PLUGIN_WEBFORM_LOAD: 66 | { 67 | addFormNote(string, F("SoftSerial: 1st=RX-Pin, 2nd=TX-Pin")); 68 | success = true; 69 | break; 70 | } 71 | 72 | case PLUGIN_WEBFORM_SAVE: 73 | { 74 | success = true; 75 | break; 76 | } 77 | 78 | case PLUGIN_READ: 79 | { 80 | if (PLUGIN_171_DEBUG) { 81 | String log = F("PZEM004T: Reading started."); 82 | addLog(LOG_LEVEL_INFO, log); 83 | } 84 | float pzVoltage = Plugin171_ReadVoltage(); 85 | float pzCurrent = Plugin171_ReadCurrent(); 86 | float pzPower = Plugin171_ReadPower(); 87 | float pzEnergy = Plugin171_ReadEnergy(); 88 | //------------------------------------------------------------------- 89 | // readings can be ZERO if there's no AC input on the module. 90 | // in this case V A and W are reported correctly as ZERO but 91 | // the accumulated Energy paramenter will not be saved so to 92 | // preserve previous value 93 | //------------------------------------------------------------------- 94 | UserVar[event->BaseVarIndex] = pzVoltage; 95 | UserVar[event->BaseVarIndex + 1] = pzCurrent; 96 | UserVar[event->BaseVarIndex + 2] = pzPower; 97 | if (pzEnergy>=0) UserVar[event->BaseVarIndex + 3] = pzEnergy; 98 | if (PLUGIN_171_DEBUG) { 99 | String log = F("PZEM004T: Reading completed."); 100 | addLog(LOG_LEVEL_INFO, log); 101 | } 102 | success = true; 103 | break; 104 | } 105 | 106 | case PLUGIN_INIT: 107 | { 108 | if (!Plugin_171_pzem) 109 | { 110 | int pzemRXpin = Settings.TaskDevicePin1[event->TaskIndex]; 111 | int pzemTXpin = Settings.TaskDevicePin2[event->TaskIndex]; 112 | Plugin_171_pzem = new PZEM004T(pzemRXpin, pzemTXpin); 113 | if (PLUGIN_171_DEBUG) { 114 | String log = F("PZEM004T: Object Initialized"); 115 | log += F(" - RX-Pin="); log += pzemRXpin; 116 | log += F(" - TX-Pin="); log += pzemTXpin; 117 | addLog(LOG_LEVEL_INFO, log); 118 | } 119 | Plugin_171_pzem->setAddress(pzemIP); // This initializes the PZEM004T library using a (useless) fake IP address 120 | if (PLUGIN_171_DEBUG) { 121 | String log = F("PZEM004T: setup address (dummy)"); 122 | log += F(" - "); log += pzemIP; 123 | addLog(LOG_LEVEL_INFO, log); 124 | } 125 | } 126 | success = true; 127 | break; 128 | } 129 | 130 | } 131 | return success; 132 | } 133 | 134 | //************************************// 135 | //***** reading values functions *****// 136 | //************************************// 137 | 138 | // NOTE: readings are attempted only PZEM_AMX_ATTEMPT times 139 | 140 | float Plugin171_ReadVoltage() { 141 | int counter = 0; 142 | float reading = -1.0; 143 | do { 144 | reading = Plugin_171_pzem->voltage(pzemIP); 145 | wdt_reset(); 146 | counter++; 147 | } while (counter < PZEM_MAX_ATTEMPT && reading < 0.0); 148 | if (reading == -1) reading = 0; 149 | return reading; 150 | } 151 | 152 | float Plugin171_ReadCurrent() { 153 | int counter = 0; 154 | float reading = -1.0; 155 | do { 156 | reading = Plugin_171_pzem->current(pzemIP); 157 | wdt_reset(); 158 | counter++; 159 | } while (counter < PZEM_MAX_ATTEMPT && reading < 0.0); 160 | if (reading == -1) reading = 0; 161 | return reading; 162 | } 163 | 164 | float Plugin171_ReadPower() { 165 | int counter = 0; 166 | float reading = -1.0; 167 | do { 168 | reading = Plugin_171_pzem->power(pzemIP); 169 | wdt_reset(); 170 | counter++; 171 | } while (counter < PZEM_MAX_ATTEMPT && reading < 0.0); 172 | if (reading == -1) reading = 0; 173 | return reading; 174 | } 175 | 176 | float Plugin171_ReadEnergy() { 177 | int counter = 0; 178 | float reading = -1.0; 179 | do { 180 | reading = Plugin_171_pzem->energy(pzemIP); 181 | wdt_reset(); 182 | counter++; 183 | } while (counter < PZEM_MAX_ATTEMPT && reading < 0.0); 184 | return reading; 185 | } 186 | //#endif 187 | -------------------------------------------------------------------------------- /_P178_SCD30.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //############ Plugin 178 SCD30 I2C CO2, Humidity and Temperature Sensor ################################ 3 | //####################################################################################################### 4 | // development version 5 | // by: V0JT4 6 | // this plugin is based on the Frogmore42 library 7 | // written based code from https://github.com/Frogmore42/Sonoff-Tasmota/tree/development/lib/FrogmoreScd30 8 | // Commands: 9 | // SCDGETABC - shows automatic calibration period in days, 0 = disable 10 | // SCDGETALT - shows altitude compensation configuration in meters above sea level 11 | // SCDGETTMP - hows temperature offset in C 12 | 13 | #define PLUGIN_178 14 | #define PLUGIN_ID_178 178 15 | #define PLUGIN_NAME_178 "Gases - CO2 SCD30" 16 | #define PLUGIN_VALUENAME1_178 "CO2" 17 | #define PLUGIN_VALUENAME2_178 "Humidity" 18 | #define PLUGIN_VALUENAME3_178 "Temperature" 19 | #define PLUGIN_VALUENAME4_178 "CO2raw" 20 | 21 | #include "FrogmoreScd30.h" 22 | boolean Plugin_178_init = false; 23 | FrogmoreScd30 scd30; 24 | 25 | boolean plugin_178_begin() 26 | { 27 | if (!Plugin_178_init) 28 | { 29 | //Wire.begin(); called in ESPEasy framework 30 | scd30.begin(); 31 | uint16_t calibration = 0; 32 | scd30.getCalibrationType(&calibration); 33 | if (calibration) 34 | { 35 | scd30.setManualCalibration(); 36 | } 37 | scd30.beginMeasuring(); 38 | Plugin_178_init = true; 39 | } 40 | return(true); 41 | } 42 | 43 | boolean Plugin_178(byte function, struct EventStruct *event, String& string) 44 | { 45 | boolean success = false; 46 | 47 | switch (function) 48 | { 49 | case PLUGIN_DEVICE_ADD: 50 | { 51 | Device[++deviceCount].Number = PLUGIN_ID_178; 52 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 53 | Device[deviceCount].VType = SENSOR_TYPE_QUAD; 54 | Device[deviceCount].Ports = 0; 55 | Device[deviceCount].PullUpOption = false; 56 | Device[deviceCount].InverseLogicOption = false; 57 | Device[deviceCount].FormulaOption = true; 58 | Device[deviceCount].ValueCount = 4; 59 | Device[deviceCount].SendDataOption = true; 60 | Device[deviceCount].TimerOption = true; 61 | Device[deviceCount].GlobalSyncOption = true; 62 | break; 63 | } 64 | 65 | case PLUGIN_GET_DEVICENAME: 66 | { 67 | string = F(PLUGIN_NAME_178); 68 | break; 69 | } 70 | 71 | case PLUGIN_GET_DEVICEVALUENAMES: 72 | { 73 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_178)); 74 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_178)); 75 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_178)); 76 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[3], PSTR(PLUGIN_VALUENAME4_178)); 77 | break; 78 | } 79 | 80 | case PLUGIN_WEBFORM_LOAD: 81 | { 82 | addFormNumericBox(F("Altitude"), F("plugin_178_SCD30_alt"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 83 | addUnit(F("m")); 84 | addFormTextBox(F("Temp offset"), F("plugin_178_SCD30_tmp"), String(PCONFIG_FLOAT(0), 2), 5); 85 | addUnit(F("C")); 86 | addHtml(F("Tools->Advanced->I2C ClockStretchLimit should be set to 20000")); 87 | success = true; 88 | break; 89 | } 90 | 91 | case PLUGIN_WEBFORM_SAVE: 92 | { 93 | uint16_t alt = getFormItemInt(F("plugin_178_SCD30_alt")); 94 | if (alt > 2000) alt = 2000; 95 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = alt; 96 | PCONFIG_FLOAT(0) = getFormItemFloat(F("plugin_178_SCD30_tmp")); 97 | success = true; 98 | break; 99 | } 100 | case PLUGIN_INIT: 101 | { 102 | plugin_178_begin(); 103 | scd30.setAltitudeCompensation(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 104 | scd30.setTemperatureOffset(PCONFIG_FLOAT(0)); 105 | break; 106 | } 107 | case PLUGIN_READ: 108 | { 109 | plugin_178_begin(); 110 | uint16_t scd30_CO2 = 0; 111 | uint16_t scd30_CO2EAvg = 0; 112 | float scd30_Humid = 0.0; 113 | float scd30_Temp = 0.0; 114 | switch (scd30.readMeasurement(&scd30_CO2, &scd30_CO2EAvg, &scd30_Temp, &scd30_Humid)) 115 | { 116 | case ERROR_SCD30_NO_ERROR: 117 | UserVar[event->BaseVarIndex] = scd30_CO2EAvg; 118 | UserVar[event->BaseVarIndex+1] = scd30_Humid; 119 | UserVar[event->BaseVarIndex+2] = scd30_Temp; 120 | UserVar[event->BaseVarIndex+3] = scd30_CO2; 121 | if (scd30_CO2EAvg > 5000) 122 | { 123 | addLog(LOG_LEVEL_INFO,F("SCD30: Sensor saturated! > 5000 ppm")); 124 | } 125 | break; 126 | case ERROR_SCD30_NO_DATA: 127 | case ERROR_SCD30_CRC_ERROR: 128 | case ERROR_SCD30_CO2_ZERO: 129 | break; 130 | default: 131 | { 132 | scd30.softReset(); 133 | } 134 | break; 135 | } 136 | success = true; 137 | break; 138 | } 139 | case PLUGIN_WRITE: 140 | { 141 | uint16_t value = 0; 142 | String log = F(""); 143 | float temp; 144 | if (string.equalsIgnoreCase(F("SCDGETABC"))) 145 | { 146 | scd30.getCalibrationType(&value); 147 | log += F("ABC: "); 148 | log += value; 149 | } else if (string.equalsIgnoreCase(F("SCDGETALT"))) 150 | { 151 | scd30.getAltitudeCompensation(&value); 152 | log += F("Altitude: "); 153 | log += value; 154 | } else if (string.equalsIgnoreCase(F("SCDGETTMP"))) 155 | { 156 | scd30.getTemperatureOffset(&temp); 157 | log += F("Temp offset: "); 158 | log += String(temp,2); 159 | } else 160 | { 161 | break; 162 | } 163 | SendStatus(event->Source, log); 164 | success = true; 165 | break; 166 | } 167 | } 168 | return success; 169 | } 170 | -------------------------------------------------------------------------------- /_P180_Mux.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 180: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_180 6 | #define PLUGIN_ID_180 180 7 | #define PLUGIN_NAME_180 "Mux Analog input - 74151/74152/74153 [TESTING]" 8 | #define PLUGIN_VALUENAME1_180 "Analog" 9 | boolean Plugin_180(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_180; 19 | Device[deviceCount].Type = DEVICE_TYPE_TRIPLE; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].Ports = 8; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = true; 25 | Device[deviceCount].ValueCount = 1; 26 | Device[deviceCount].SendDataOption = true; 27 | Device[deviceCount].TimerOption = true; 28 | Device[deviceCount].GlobalSyncOption = true; 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_180); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_180)); 41 | break; 42 | } 43 | case PLUGIN_INIT: 44 | { 45 | int availablePorts=1; 46 | if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 47 | { 48 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 49 | availablePorts*=2; 50 | } 51 | if (Settings.TaskDevicePin2[event->TaskIndex] != -1) 52 | { 53 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], OUTPUT); 54 | availablePorts*=2; 55 | } 56 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 57 | { 58 | pinMode(Settings.TaskDevicePin3[event->TaskIndex], OUTPUT); 59 | availablePorts*=2; 60 | } 61 | String log = F("Mux available ports : "); 62 | log += availablePorts; 63 | addLog(LOG_LEVEL_INFO,log); 64 | success = true; 65 | break; 66 | } 67 | case PLUGIN_READ: 68 | { 69 | String log = F("ADC : Analog port "); 70 | log += Settings.TaskDevicePort[event->TaskIndex]; 71 | log += F(" mux address: "); 72 | switch( Settings.TaskDevicePort[event->TaskIndex] ) 73 | { 74 | case 1: 75 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); 76 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); 77 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], HIGH); 78 | log += " 001 "; 79 | break; 80 | case 2: 81 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); 82 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); 83 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], LOW); 84 | log += " 010 "; 85 | break; 86 | case 3: 87 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); 88 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); 89 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], HIGH); 90 | log += " 011 "; 91 | break; 92 | case 4: 93 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); 94 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); 95 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], LOW); 96 | log += " 100 "; 97 | break; 98 | case 5: 99 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); 100 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); 101 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], HIGH); 102 | log += " 101 "; 103 | break; 104 | case 6: 105 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); 106 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); 107 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], LOW); 108 | log += " 110 "; 109 | break; 110 | case 7: 111 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); 112 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); 113 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], HIGH); 114 | log += " 111 "; 115 | break; 116 | default : 117 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); 118 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); 119 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], LOW); 120 | log += " 000 "; 121 | } 122 | 123 | UserVar[event->BaseVarIndex] = analogRead(A0); 124 | 125 | log += F("value: "); 126 | log += UserVar[event->BaseVarIndex]; 127 | addLog(LOG_LEVEL_INFO,log); 128 | success = true; 129 | break; 130 | } 131 | } 132 | return success; 133 | } -------------------------------------------------------------------------------- /_P184_GY_US42V2.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################### Plugin 184: GY_US42V2 Ultrasonic range finder sensor ############################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_184 6 | #define PLUGIN_ID_184 184 7 | #define PLUGIN_NAME_184 "Ultrasonic range finder - GY-US42V2" 8 | #define PLUGIN_VALUENAME1_184 "DISTANCE" 9 | 10 | #define GY_US42V2_ADDRESS (0x70) // default address (0x70 = datasheet address 0xE0) 11 | #define GY_US42V2_CMD_RANGE_COMMAND (0x51) 12 | 13 | boolean Plugin_184(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_184; 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].FormulaOption = true; 29 | Device[deviceCount].ValueCount = 1; 30 | Device[deviceCount].SendDataOption = true; 31 | Device[deviceCount].TimerOption = true; 32 | Device[deviceCount].GlobalSyncOption = true; 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICENAME: 37 | { 38 | string = F(PLUGIN_NAME_184); 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICEVALUENAMES: 43 | { 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_184)); 45 | break; 46 | } 47 | 48 | case PLUGIN_WEBFORM_LOAD: 49 | { 50 | success = true; 51 | break; 52 | } 53 | 54 | case PLUGIN_WEBFORM_SAVE: 55 | { 56 | success = true; 57 | break; 58 | } 59 | 60 | case PLUGIN_INIT: 61 | { 62 | Plugin_184_begin(); 63 | success = true; 64 | break; 65 | } 66 | 67 | case PLUGIN_READ: 68 | { 69 | uint16_t value; 70 | value = Plugin_184_getDistance(); 71 | UserVar[event->BaseVarIndex] = value; 72 | String log = F("P184 : distance = "); 73 | log += value; 74 | log += F(" cm"); 75 | addLog(LOG_LEVEL_INFO,log); 76 | success = true; 77 | break; 78 | } 79 | } 80 | return success; 81 | } 82 | 83 | //**************************************************************************/ 84 | // Sensor setup 85 | //**************************************************************************/ 86 | void Plugin_184_begin(void) 87 | { 88 | } 89 | 90 | //**************************************************************************/ 91 | // Report distance 92 | //**************************************************************************/ 93 | uint16_t Plugin_184_getDistance() 94 | { 95 | uint16_t value = 0; 96 | 97 | Wire.beginTransmission(GY_US42V2_ADDRESS); 98 | Wire.write(GY_US42V2_CMD_RANGE_COMMAND); 99 | Wire.endTransmission(); 100 | 101 | delay(70); // transmit -> receive turnaround time (up to 65ms) 102 | 103 | Wire.requestFrom(GY_US42V2_ADDRESS, 2); 104 | if (Wire.available() > 1) { 105 | value = ((Wire.read() << 8) | Wire.read()); 106 | } 107 | 108 | return value; 109 | } 110 | -------------------------------------------------------------------------------- /_P203_Feeder.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################################ Plugin 203: Pet feeder ########################################### 3 | //####################################################################################################### 4 | //############################### Plugin for ESP Easy by DatuX ############################### 5 | //################################### http://www.datux.nl ############################################## 6 | //####################################################################################################### 7 | 8 | 9 | 10 | #ifdef PLUGIN_BUILD_TESTING 11 | 12 | #define PLUGIN_203 13 | #define PLUGIN_ID_203 203 14 | #define PLUGIN_NAME_203 "Automated pet feeder [TESTING]" 15 | 16 | #ifndef CONFIG 17 | #define CONFIG(n) (Settings.TaskDevicePluginConfig[event->TaskIndex][n]) 18 | #endif 19 | 20 | 21 | 22 | //to not scare the cat of sudden motor movements 23 | //attack and sustain in mS 24 | void ramped_pulse(byte pin, unsigned long attack, unsigned long sustain) 25 | { 26 | 27 | //attack 28 | unsigned long start_time=millis(); 29 | while (millis()-start_time < attack) 30 | { 31 | analogWrite(pin, ((millis()-start_time) * PWMRANGE /attack ) ); 32 | yield(); 33 | } 34 | 35 | //sustain 36 | analogWrite(pin, PWMRANGE); 37 | // digitalWrite(pin, HIGH); 38 | delay(sustain); 39 | 40 | //releaase 41 | start_time=millis(); 42 | while (millis()-start_time < attack) 43 | { 44 | analogWrite(pin, PWMRANGE-(((millis()-start_time) * PWMRANGE / attack) )); 45 | yield(); 46 | } 47 | 48 | //make sure its really off 49 | analogWrite(pin, 0); 50 | // digitalWrite(pin, LOW); 51 | } 52 | 53 | boolean Plugin_203(byte function, struct EventStruct *event, String& string) 54 | { 55 | boolean success = false; 56 | 57 | switch (function) 58 | { 59 | case PLUGIN_DEVICE_ADD: 60 | { 61 | Device[++deviceCount].Number = PLUGIN_ID_203; 62 | Device[deviceCount].Type = DEVICE_TYPE_TRIPLE; 63 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 64 | Device[deviceCount].Ports = 0; 65 | Device[deviceCount].PullUpOption = false; 66 | Device[deviceCount].InverseLogicOption = false; 67 | Device[deviceCount].FormulaOption = false; 68 | Device[deviceCount].ValueCount = 1; 69 | Device[deviceCount].SendDataOption = true; 70 | Device[deviceCount].TimerOption = false; 71 | Device[deviceCount].GlobalSyncOption = false; 72 | break; 73 | } 74 | 75 | case PLUGIN_GET_DEVICENAME: 76 | { 77 | string = F(PLUGIN_NAME_203); 78 | break; 79 | } 80 | 81 | case PLUGIN_GET_DEVICEVALUENAMES: 82 | { 83 | break; 84 | } 85 | 86 | case PLUGIN_WEBFORM_LOAD: 87 | { 88 | 89 | addFormNumericBox(F("Rotate forward time"), F("forward"), CONFIG(0), 0, 60000); 90 | addUnit(F("ms")); 91 | addFormNumericBox(F("Rotate reverse time"), F("reverse"), CONFIG(1), 0, 60000); 92 | addUnit(F("ms")); 93 | 94 | 95 | 96 | success = true; 97 | break; 98 | } 99 | 100 | case PLUGIN_WEBFORM_SAVE: 101 | { 102 | CONFIG(0) = getFormItemInt(F("forward")); 103 | CONFIG(1) = getFormItemInt(F("reverse")); 104 | 105 | success = true; 106 | break; 107 | } 108 | 109 | case PLUGIN_INIT: 110 | { 111 | pinMode(Settings.TaskDevicePin1[event->TaskIndex],OUTPUT); 112 | pinMode(Settings.TaskDevicePin2[event->TaskIndex],OUTPUT); 113 | pinMode(Settings.TaskDevicePin3[event->TaskIndex],OUTPUT); 114 | // analogWriteFreq(30000); 115 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); //disable 116 | success = true; 117 | break; 118 | } 119 | 120 | 121 | 122 | case PLUGIN_WRITE: 123 | { 124 | 125 | String command = parseString(string, 1); 126 | 127 | if (command == F("feed")) 128 | { 129 | // for(int i=0; iPar1; i++) 130 | { 131 | //forward 132 | // digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); //enable 133 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); 134 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], LOW); 135 | 136 | ramped_pulse(Settings.TaskDevicePin1[event->TaskIndex], event->Par1, CONFIG(0)); 137 | // delay(CONFIG(0)); 138 | 139 | //pause 140 | // digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); //disable 141 | // delay(100); 142 | 143 | //reverse 144 | // digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH); //enable 145 | digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); 146 | digitalWrite(Settings.TaskDevicePin3[event->TaskIndex], HIGH); 147 | ramped_pulse(Settings.TaskDevicePin1[event->TaskIndex], 1000, CONFIG(1)); 148 | // delay(CONFIG(1)); 149 | 150 | //pause 151 | // digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW); //disable 152 | // delay(100); 153 | 154 | } 155 | 156 | 157 | } 158 | 159 | 160 | success=true; 161 | break; 162 | } 163 | 164 | } 165 | return success; 166 | } 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /_P211_MPU6050.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################################ Plugin 211: MPU6050: motion detection ################################ 3 | //####################################################################################################### 4 | // 5 | // This plugin uses the MPU6050 accelerometer & gyro to detect motion. The motion threshold can be 6 | // configured directly on the UI. 7 | // 8 | // NOTE: requires the following libraries: 9 | // 10 | // * MPU6050: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050 11 | // * I2CDEV: https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/I2Cdev 12 | //####################################################################################################### 13 | 14 | #include "Wire.h" 15 | #include "MPU6050.h" 16 | 17 | MPU6050 *mpu; 18 | 19 | int16_t motion = 0; 20 | 21 | #define PLUGIN_211 22 | #define PLUGIN_ID_211 211 23 | #define PLUGIN_NAME_211 "Motion Detection - MPU6050" 24 | #define PLUGIN_VALUENAME1_211 "Motion" 25 | 26 | #define MPU6050_ADDRESS 0x68 // I2C address 27 | 28 | boolean Plugin_211(byte function, struct EventStruct *event, String& string) 29 | { 30 | boolean success = false; 31 | 32 | switch (function) 33 | { 34 | case PLUGIN_DEVICE_ADD: 35 | { 36 | Device[++deviceCount].Number = PLUGIN_ID_211; 37 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 38 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 39 | Device[deviceCount].Ports = 0; 40 | Device[deviceCount].PullUpOption = false; 41 | Device[deviceCount].InverseLogicOption = false; 42 | Device[deviceCount].FormulaOption = false; 43 | Device[deviceCount].ValueCount = 1; 44 | Device[deviceCount].SendDataOption = true; 45 | Device[deviceCount].TimerOption = true; 46 | Device[deviceCount].GlobalSyncOption = true; 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICENAME: 51 | { 52 | string = F(PLUGIN_NAME_211); 53 | break; 54 | } 55 | 56 | case PLUGIN_GET_DEVICEVALUENAMES: 57 | { 58 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_211)); 59 | break; 60 | } 61 | 62 | case PLUGIN_WEBFORM_LOAD: 63 | { 64 | char tmpString[128]; 65 | sprintf_P(tmpString, PSTR("Motion threshold:"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]); 66 | string += tmpString; 67 | 68 | sprintf_P(tmpString, PSTR("Stop threshold:"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]); 69 | string += tmpString; 70 | 71 | success = true; 72 | break; 73 | } 74 | 75 | case PLUGIN_WEBFORM_SAVE: 76 | { 77 | int16_t motion_threshold = WebServer.arg("plugin_211_motion_threshold").toInt(); 78 | ExtraTaskSettings.TaskDevicePluginConfigLong[0] = motion_threshold; 79 | 80 | int16_t stop_threshold = WebServer.arg("plugin_211_stop_threshold").toInt(); 81 | ExtraTaskSettings.TaskDevicePluginConfigLong[1] = stop_threshold; 82 | 83 | mpu->setMotionDetectionThreshold(motion_threshold); 84 | mpu->setZeroMotionDetectionThreshold(stop_threshold); 85 | 86 | success = true; 87 | break; 88 | } 89 | 90 | case PLUGIN_INIT: 91 | { 92 | addLog(LOG_LEVEL_INFO, "MPU-6050 : Init"); 93 | 94 | // Load saved threshold settings. 95 | LoadTaskSettings(event->TaskIndex); 96 | 97 | // Initialize MPU sensor. 98 | mpu = new MPU6050(MPU6050_ADDRESS); 99 | mpu->initialize(); 100 | 101 | // Enable Zero Motion Detection interrupt. 102 | mpu->setIntFreefallEnabled(false); 103 | mpu->setIntZeroMotionEnabled(false); 104 | mpu->setIntMotionEnabled(false); 105 | 106 | // Set accelerometer power-on delay (3 ms). 107 | mpu->setAccelerometerPowerOnDelay(3); 108 | 109 | // Set high-pass filter configuration in mode 1 (5Hz) for improved motion detection. 110 | mpu->setDHPFMode(1); 111 | 112 | // Set motion detection event acceleration threshold. Motion is detected when the 113 | // absolute value of any of the accelerometer measurements exceeds this Motion 114 | // detection threshold. 115 | mpu->setMotionDetectionThreshold(ExtraTaskSettings.TaskDevicePluginConfigLong[0] ?: 4); 116 | 117 | // Set zero motion detection event acceleration threshold. 118 | mpu->setZeroMotionDetectionThreshold(ExtraTaskSettings.TaskDevicePluginConfigLong[1] ?: 4); 119 | 120 | // Set motion detection event duration threshold. The Motion detection duration 121 | // counter increments when the absolute value of any of the accelerometer 122 | // measurements exceeds the Motion detection threshold (Register 31). The Motion 123 | // detection interrupt is triggered when the Motion detection counter reaches 124 | // the time count specified in this register. 125 | mpu->setMotionDetectionDuration(4); 126 | 127 | // Set zero motion detection event duration threshold. The Zero Motion duration counter 128 | // increments while the absolute value of the accelerometer measurements are each 129 | // less than the detection threshold (Register 33). The Zero Motion interrupt is 130 | // triggered when the Zero Motion duration counter reaches the time count specified 131 | // in this register. 132 | mpu->setZeroMotionDetectionDuration(4); 133 | 134 | success = true; 135 | break; 136 | } 137 | 138 | case PLUGIN_ONCE_A_SECOND: 139 | { 140 | // If any axis has motion, then increment motion. 141 | if (mpu->getMotionStatus() > 1) { 142 | motion++; 143 | } 144 | 145 | success = true; 146 | break; 147 | } 148 | 149 | case PLUGIN_READ: 150 | { 151 | // Convert motion to a percentage that represents how much motion there was 152 | // in the last X seconds, where X is the configured polling delay. 153 | UserVar[event->BaseVarIndex] = ((float) motion / Settings.TaskDeviceTimer[event->TaskIndex]) * 100; 154 | 155 | // Reset motion. 156 | motion = 0; 157 | 158 | String log = F("MPU6050 : Reporting motion: "); 159 | log += UserVar[event->BaseVarIndex]; 160 | addLog(LOG_LEVEL_DEBUG, log); 161 | 162 | sendData(event); 163 | 164 | success = true; 165 | break; 166 | } 167 | } 168 | 169 | return success; 170 | } 171 | -------------------------------------------------------------------------------- /_P212_MY9291.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 212: MY9291 Basic ######################################### 3 | //####################################################################################################### 4 | 5 | // The MY9291 led driver is a device found in smart lightbulbs such as the AI Thinker AILight and many 6 | // other bulbs that are either clones or licenced designs. This plugin offers RGBW control of these 7 | // bulbs. The plugin is designed to control 4 channels, the MY9291 can be used in 3 channel mode as well 8 | // 3 Channel should work I think, but is untested 9 | 10 | // This plugin requires modification of the EventStruct in order to function. A Par4 integer needs to be 11 | // added currently. The parseCommandString function will also need to be updated as well. 12 | 13 | // The MY9291 library (from tinkerman) is required for this plugin to function correctly. 14 | // https://github.com/xoseperez/my9291 15 | 16 | // Although the MY9291 led driver can operate in 8bit, 16bit and 32bit modes, the default for the MY9291 17 | // is used. This offers 8bit control of each channel i.e. a 32bit command is sent on each change 18 | 19 | // List of commands: 20 | // (1) MY9291,,,, 21 | 22 | // Usage: 23 | // (1): Set RGBW Color to specified LED number (eg. MY9291,255,255,255,20) 24 | 25 | #include 26 | my9291 *Plugin_212_rgbw; 27 | 28 | #define PLUGIN_212 29 | #define PLUGIN_ID_212 212 30 | #define PLUGIN_NAME_212 "MY9291" 31 | #define PLUGIN_VALUENAME1_212 "RGB" 32 | 33 | boolean Plugin_212(byte function, struct EventStruct *event, String& string) 34 | { 35 | boolean success = false; 36 | 37 | switch (function) 38 | { 39 | 40 | case PLUGIN_DEVICE_ADD: 41 | { 42 | Device[++deviceCount].Number = PLUGIN_ID_212; 43 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 44 | Device[deviceCount].Custom = true; 45 | Device[deviceCount].TimerOption = false; 46 | break; 47 | } 48 | 49 | case PLUGIN_GET_DEVICENAME: 50 | { 51 | string = F(PLUGIN_NAME_212); 52 | break; 53 | } 54 | 55 | case PLUGIN_GET_DEVICEVALUENAMES: 56 | { 57 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_212)); 58 | break; 59 | } 60 | 61 | case PLUGIN_WEBFORM_LOAD: 62 | { 63 | char tmpString[128]; 64 | 65 | string += F("DI Pin:"); 66 | addPinSelect(false, string, "taskdevicepin1", Settings.TaskDevicePin1[event->TaskIndex]); 67 | string += F("DCKI Pin:"); 68 | addPinSelect(false, string, "taskdevicepin2", Settings.TaskDevicePin2[event->TaskIndex]); 69 | 70 | success = true; 71 | break; 72 | } 73 | 74 | case PLUGIN_WEBFORM_SAVE: 75 | { 76 | success = true; 77 | break; 78 | } 79 | 80 | case PLUGIN_INIT: 81 | { 82 | if (!Plugin_212_rgbw) 83 | { 84 | Plugin_212_rgbw = new my9291(Settings.TaskDevicePin1[event->TaskIndex], Settings.TaskDevicePin2[event->TaskIndex], MY9291_COMMAND_DEFAULT); 85 | Plugin_212_rgbw->setState(true); 86 | } 87 | success = true; 88 | break; 89 | } 90 | 91 | case PLUGIN_WRITE: 92 | { 93 | if (Plugin_212_rgbw) 94 | { 95 | String tmpString = string; 96 | int argIndex = tmpString.indexOf(','); 97 | if (argIndex) 98 | tmpString = tmpString.substring(0, argIndex); 99 | 100 | if (tmpString.equalsIgnoreCase(F("MY9291"))) 101 | { 102 | Plugin_212_rgbw->setColor((my9291_color_t) { event->Par1, event->Par2, event->Par3, event->Par4 }); 103 | Plugin_212_rgbw->setState(true); 104 | success = true; 105 | } 106 | } 107 | 108 | break; 109 | } 110 | return success; 111 | } 112 | } 113 | 114 | -------------------------------------------------------------------------------- /_P213_VEML6070: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 213 VEML6070 Ultraviolet Sensor ####################### 3 | //#################### based on Adafruit Library ####################### 4 | //####################################################################################################### 5 | 6 | #define PLUGIN_213 7 | #define PLUGIN_ID_213 213 8 | #define PLUGIN_NAME_213 "UV - VEML6070" 9 | #define PLUGIN_VALUENAME1_213 "UV" 10 | 11 | // See also VEML6070 data sheet:http://www.vishay.com/docs/84277/veml6070.pdf 12 | // 13 | //////////////////////////// 14 | // VEML6070 Registers/addresses // 15 | //////////////////////////// 16 | 17 | #define VEML6070_ADDR_ARA 0x19 >> 1 // shift by one to get correct register addresses 18 | #define VEML6070_ADDR_CMD 0x70 >> 1 19 | #define VEML6070_ADDR_DATA_LSB 0x71 >> 1 20 | #define VEML6070_ADDR_DATA_MSB 0x73 >> 1 21 | 22 | // really unusual way of getting data, your read from two different addrs! 23 | #define VEML6070_ADDR_H 0x39 24 | #define VEML6070_ADDR_L 0x38 25 | 26 | // VEML6070 command register bits 27 | #define VEML6070_CMD_DISABLE 0x01 28 | #define VEML6070_CMD_WDM 0x02 29 | 30 | // three different integration times 31 | typedef enum veml6070_integrationtime { 32 | VEML6070_HALF_T, 33 | VEML6070_1_T, 34 | VEML6070_2_T, 35 | VEML6070_4_T, 36 | } veml6070_integrationtime_t; 37 | 38 | bool Plugin_213_begin(veml6070_integrationtime_t itime); 39 | uint16_t Plugin_213_readUV(); 40 | uint16_t Plugin_213_convert_to_risk_level(uint16_t uvs_step); 41 | 42 | boolean Plugin_213(byte function, struct EventStruct *event, String& string) 43 | { 44 | boolean success = false; 45 | 46 | switch (function) 47 | { 48 | case PLUGIN_DEVICE_ADD: 49 | { 50 | Device[++deviceCount].Number = PLUGIN_ID_213; 51 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 52 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 53 | Device[deviceCount].Ports = 0; 54 | Device[deviceCount].PullUpOption = false; 55 | Device[deviceCount].InverseLogicOption = false; 56 | Device[deviceCount].FormulaOption = true; 57 | Device[deviceCount].ValueCount = 1; 58 | Device[deviceCount].SendDataOption = true; 59 | Device[deviceCount].TimerOption = true; 60 | Device[deviceCount].GlobalSyncOption = true; 61 | break; 62 | } 63 | 64 | case PLUGIN_GET_DEVICENAME: 65 | { 66 | string = F(PLUGIN_NAME_213); 67 | break; 68 | } 69 | 70 | case PLUGIN_GET_DEVICEVALUENAMES: 71 | { 72 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_213)); 73 | break; 74 | } 75 | 76 | case PLUGIN_READ: 77 | { 78 | if (!Plugin_213_begin(VEML6070_1_T)) { 79 | String log = F("VEML6070: No available!"); 80 | addLog(LOG_LEVEL_INFO, log); 81 | UserVar[event->BaseVarIndex] = NAN; 82 | success = false; 83 | } else { 84 | String s = ""; 85 | uint16_t uv; 86 | 87 | uv = Plugin_213_readUV(); 88 | if (isnan(uv) || uv == (-1) || uv == 65535) { 89 | String log = F("VEML6070: no data read!"); 90 | addLog(LOG_LEVEL_INFO, log); 91 | UserVar[event->BaseVarIndex] = NAN; 92 | success = false; 93 | } else { 94 | UserVar[event->BaseVarIndex] = uv; 95 | String log = F("VEML6070: UV: "); 96 | log += UserVar[event->BaseVarIndex]; 97 | addLog(LOG_LEVEL_INFO, log); 98 | success = true; 99 | } 100 | } 101 | 102 | break; 103 | } 104 | 105 | } 106 | return success; 107 | } 108 | 109 | //**************************************************************************/ 110 | // Check VEML6070 presence 111 | //**************************************************************************/ 112 | bool Plugin_213_begin(veml6070_integrationtime_t itime) { 113 | byte error; 114 | 115 | Wire.begin(); 116 | Wire.beginTransmission(VEML6070_ADDR_L); 117 | Wire.write((itime << 2) | VEML6070_CMD_WDM); 118 | error = Wire.endTransmission(); 119 | delay(500); 120 | 121 | return (error == 0); 122 | } 123 | 124 | /* 125 | Die Sonnenleistung berechne ich mit einer Simplen Formel 126 | WATT = ((uv.readUV() * 2.5) / 187) * 10; 127 | Allerdings benutze ich einen VEML6070 UV Sensor via I2C. 128 | Kann aber nicht bestätigen ob dieser Wert auch stimmt aber laut meinem Gefühl könnte es schon hinkommen. 129 | */ 130 | // UV = uv.readUV()/684.75; 131 | //  WATT = ((uv.readUV() * 2.5) / 187) * 10; 132 | 133 | uint16_t Plugin_213_readUV() { 134 | if (Wire.requestFrom(VEML6070_ADDR_H, 1) != 1) return -1; 135 | uint16_t uvi = Wire.read(); 136 | uvi <<= 8; 137 | if (Wire.requestFrom(VEML6070_ADDR_L, 1) != 1) return -1; 138 | uvi |= Wire.read(); 139 | 140 | return uvi; 141 | } 142 | 143 | uint16_t Plugin_213_convert_to_risk_level(uint16_t uvs_step) { 144 | uint16_t risk_level_mapping_table[4] = {2241, 4482, 5976, 8217}; 145 | uint16_t i; 146 | for (i = 0; i < 4; i++) { 147 | if (uvs_step <= risk_level_mapping_table[i]) { 148 | break; 149 | } 150 | } 151 | return i; 152 | } 153 | -------------------------------------------------------------------------------- /_P217_ACS712AC.ino: -------------------------------------------------------------------------------- 1 | 2 | #ifdef PLUGIN_BUILD_DEV 3 | 4 | //Plugin to measure AC current using a ACS712 module. Very much a work in progress. 5 | //For my lab, i have used R1=1200 and R2=2000 6 | #define PLUGIN_217 7 | #define PLUGIN_ID_217 217 //plugin id 8 | #define PLUGIN_NAME_217 "Energy (AC) - ACS712 [DEVELOPMENT]" //"Plugin Name" is what will be dislpayed in the selection list 9 | #define PLUGIN_VALUENAME1_217 "A" //variable output of the plugin. The label is in quotation marks 10 | #define PLUGIN_217_DEBUG true //set to true for extra log info in the debug 11 | #define PLUGIN_217_MODEL_5A 185 12 | #define PLUGIN_217_MODEL_20A 100 13 | #define PLUGIN_217_MODEL_30A 66 14 | 15 | boolean Plugin_217(byte function, struct EventStruct *event, String& string) 16 | { 17 | boolean success = false; 18 | switch (function) 19 | { 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | 23 | //This case defines the device characteristics, edit appropriately 24 | 25 | Device[++deviceCount].Number = PLUGIN_ID_217; 26 | Device[deviceCount].Type = DEVICE_TYPE_ANALOG; //how the device is connected 27 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; //type of value the plugin will return, used only for Domoticz 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; //number of output variables. The value should match the number of keys PLUGIN_VALUENAME1_xxx 33 | Device[deviceCount].SendDataOption = true; 34 | Device[deviceCount].TimerOption = true; 35 | Device[deviceCount].TimerOptional = false; 36 | Device[deviceCount].GlobalSyncOption = true; 37 | Device[deviceCount].DecimalsOnly = true; 38 | break; 39 | } 40 | case PLUGIN_GET_DEVICENAME: 41 | { 42 | //return the device name 43 | string = F(PLUGIN_NAME_217); 44 | break; 45 | } 46 | case PLUGIN_GET_DEVICEVALUENAMES: 47 | { 48 | //called when the user opens the module configuration page 49 | //it allows to add a new row for each output variable of the plugin 50 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_217)); 51 | break; 52 | } 53 | case PLUGIN_WEBFORM_LOAD: 54 | { 55 | String model[3]; 56 | model[0] = F("ACS712 5A"); 57 | model[1] = F("ACS712 20A"); 58 | model[2] = F("ACS712 30A"); 59 | byte modelchoice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 60 | int modelValues[3] = { PLUGIN_217_MODEL_5A, PLUGIN_217_MODEL_20A, PLUGIN_217_MODEL_30A }; 61 | addFormSubHeader(F("Model selection")); 62 | addFormSelector(F("ACS712 model"), F("plugin_217_model"), 3, model, modelValues, modelchoice); 63 | addFormSubHeader(F("Sampling period")); 64 | addFormNumericBox(F("Sampling period in ms"), F("plugin_217_sampling_period"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]); 65 | addFormSubHeader(F("Voltage divider values")); 66 | addFormNumericBox(F("R1 Value, Ohms"), F("plugin_217_r1"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]); 67 | addFormNumericBox(F("R2 Value, Ohms"), F("plugin_217_r2"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]); 68 | addFormSubHeader(F("Result offset")); 69 | 70 | success = true; 71 | break; 72 | } 73 | case PLUGIN_WEBFORM_SAVE: 74 | { 75 | //this case defines the code to be executed when the form is submitted 76 | //the plugin settings should be saved to Settings.TaskDevicePluginConfig[event->TaskIndex][x] 77 | //ping configuration should be read from Settings.TaskDevicePin1[event->TaskIndex] and stored 78 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("plugin_217_model")); 79 | ExtraTaskSettings.TaskDevicePluginConfigLong[0] = getFormItemInt(F("plugin_217_r1")); 80 | ExtraTaskSettings.TaskDevicePluginConfigLong[1] = getFormItemInt(F("plugin_217_r2")); 81 | ExtraTaskSettings.TaskDevicePluginConfigLong[2] = getFormItemInt(F("plugin_217_sampling_period")); 82 | //after the form has been saved successfuly, set success and break 83 | success = true; 84 | break; 85 | 86 | } 87 | case PLUGIN_INIT: 88 | { 89 | //this case defines code to be executed when the plugin is initialised 90 | 91 | //after the plugin has been initialised successfuly, set success and break 92 | success = true; 93 | break; 94 | 95 | } 96 | 97 | case PLUGIN_READ: 98 | { 99 | 100 | int mVperAmp = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 101 | float R1 = ExtraTaskSettings.TaskDevicePluginConfigLong[0]; 102 | float R2 = ExtraTaskSettings.TaskDevicePluginConfigLong[1]; 103 | double Voltage = 0; 104 | double VRMS = 0; 105 | double AmpsRMS = 0; 106 | double VoltageSensor = 0; 107 | Voltage = p217_get_VPP(); 108 | 109 | 110 | VoltageSensor = (Voltage*(R2/R1)); 111 | VRMS = (VoltageSensor/2.0) *0.707; 112 | AmpsRMS = (VRMS * 1000)/mVperAmp; 113 | UserVar[event->BaseVarIndex] = (float)AmpsRMS; 114 | #ifdef PLUGIN_217_DEBUG 115 | String log = ""; 116 | log = "Voltage:"; 117 | log += String(Voltage); 118 | log += ", R1:"; 119 | log += String(R1); 120 | log += ", R2:"; 121 | log += String(R2); 122 | log += " VoltageSensor:"; 123 | log += String(VoltageSensor); 124 | log += ", AmpsRMS:"; 125 | log += String(AmpsRMS); 126 | addLog(LOG_LEVEL_INFO,String(log)); 127 | #endif 128 | success = true; 129 | break; 130 | 131 | } 132 | case PLUGIN_EXIT: 133 | { 134 | //perform cleanup tasks here. For example, free memory 135 | 136 | break; 137 | 138 | } 139 | 140 | case PLUGIN_ONCE_A_SECOND: 141 | { 142 | //code to be executed once a second. Tasks which do not require fast response can be added here 143 | success = true; 144 | } 145 | } 146 | return success; 147 | } 148 | 149 | float p217_get_VPP() 150 | { 151 | long timePassedSince(unsigned long timestamp); 152 | boolean timeOutReached(unsigned long timer); 153 | float sampling_period = ExtraTaskSettings.TaskDevicePluginConfigLong[2]; 154 | const int sensorIn = A0; 155 | float result; 156 | int readValue; //value read from the sensor 157 | int maxValue = 0; // store max value here 158 | int minValue = 1024; // store min value here 159 | uint32_t start_time = millis(); 160 | uint32_t nice_time = millis(); 161 | 162 | while(timePassedSince(start_time) < sampling_period) //sample the period specified 163 | { 164 | readValue = analogRead(sensorIn); 165 | //After a friendly tip in my pull request it was suggested that one should 166 | //call delay(0) periodically to increase stability. So, lets do that every 20ms 167 | if (timePassedSince(nice_time) > 20 ){ 168 | delay(0); 169 | nice_time = millis(); 170 | } 171 | 172 | // see if you have a new maxValue 173 | if (readValue > maxValue) 174 | { 175 | /*record the maximum sensor value*/ 176 | maxValue = readValue; 177 | } 178 | if (readValue < minValue) 179 | { 180 | /*record the maximum sensor value*/ 181 | minValue = readValue; 182 | } 183 | } 184 | 185 | // Subtract min from max 186 | result = ((maxValue - minValue) * 5.0)/1024.0; 187 | 188 | return result; 189 | 190 | } 191 | #endif 192 | -------------------------------------------------------------------------------- /esp8266-oled-ssd1306.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enesbcs/ESPEasyPluginPlayground/0a4399e4342c216a91cb25d6f47e33df96a4beec/esp8266-oled-ssd1306.zip -------------------------------------------------------------------------------- /libraries _PLUGIN145 ITHO FAN/Itho/CC1101.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #include "CC1101.h" 6 | 7 | // default constructor 8 | CC1101::CC1101() 9 | { 10 | SPI.begin(); 11 | #ifdef ESP8266 12 | pinMode(SS, OUTPUT); 13 | #endif 14 | } //CC1101 15 | 16 | // default destructor 17 | CC1101::~CC1101() 18 | { 19 | } //~CC1101 20 | 21 | /***********************/ 22 | // SPI helper functions select() and deselect() 23 | inline void CC1101::select(void) { 24 | digitalWrite(SS, LOW); 25 | } 26 | 27 | inline void CC1101::deselect(void) { 28 | digitalWrite(SS, HIGH); 29 | } 30 | 31 | void CC1101::spi_waitMiso() 32 | { 33 | while(digitalRead(MISO) == HIGH) yield(); 34 | } 35 | 36 | void CC1101::init() 37 | { 38 | reset(); 39 | } 40 | 41 | void CC1101::reset() 42 | { 43 | deselect(); 44 | delayMicroseconds(5); 45 | select(); 46 | delayMicroseconds(10); 47 | deselect(); 48 | delayMicroseconds(45); 49 | select(); 50 | 51 | spi_waitMiso(); 52 | SPI.transfer(CC1101_SRES); 53 | delay(10); 54 | spi_waitMiso(); 55 | deselect(); 56 | } 57 | 58 | uint8_t CC1101::writeCommand(uint8_t command) 59 | { 60 | uint8_t result; 61 | 62 | select(); 63 | spi_waitMiso(); 64 | result = SPI.transfer(command); 65 | deselect(); 66 | 67 | return result; 68 | } 69 | 70 | void CC1101::writeRegister(uint8_t address, uint8_t data) 71 | { 72 | select(); 73 | spi_waitMiso(); 74 | SPI.transfer(address); 75 | SPI.transfer(data); 76 | deselect(); 77 | } 78 | 79 | uint8_t CC1101::readRegister(uint8_t address) 80 | { 81 | uint8_t val; 82 | 83 | select(); 84 | spi_waitMiso(); 85 | SPI.transfer(address); 86 | val = SPI.transfer(0); 87 | deselect(); 88 | 89 | return val; 90 | } 91 | 92 | uint8_t CC1101::readRegisterMedian3(uint8_t address) 93 | { 94 | uint8_t val, val1, val2, val3; 95 | 96 | select(); 97 | spi_waitMiso(); 98 | SPI.transfer(address); 99 | val1 = SPI.transfer(0); 100 | SPI.transfer(address); 101 | val2 = SPI.transfer(0); 102 | SPI.transfer(address); 103 | val3 = SPI.transfer(0); 104 | deselect(); 105 | // reverse sort (largest in val1) because this is te expected order for TX_BUFFER 106 | if (val3 > val2) {val = val3; val3 = val2; val2 = val; } //Swap(val3,val2) 107 | if (val2 > val1) {val = val2; val2 = val1, val1 = val; } //Swap(val2,val1) 108 | if (val3 > val2) {val = val3; val3 = val2, val2 = val; } //Swap(val3,val2) 109 | 110 | return val2; 111 | } 112 | 113 | /* Known SPI/26MHz synchronization bug (see CC1101 errata) 114 | This issue affects the following registers: SPI status byte (fields STATE and FIFO_BYTES_AVAILABLE), 115 | FREQEST or RSSI while the receiver is active, MARCSTATE at any time other than an IDLE radio state, 116 | RXBYTES when receiving or TXBYTES when transmitting, and WORTIME1/WORTIME0 at any time.*/ 117 | //uint8_t CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType) 118 | uint8_t /* ICACHE_RAM_ATTR */ CC1101::readRegisterWithSyncProblem(uint8_t address, uint8_t registerType) 119 | { 120 | uint8_t value1, value2; 121 | 122 | value1 = readRegister(address | registerType); 123 | 124 | //if two consecutive reads gives us the same result then we know we are ok 125 | do 126 | { 127 | value2 = value1; 128 | value1 = readRegister(address | registerType); 129 | } 130 | while (value1 != value2); 131 | 132 | return value1; 133 | } 134 | 135 | //registerType = CC1101_CONFIG_REGISTER or CC1101_STATUS_REGISTER 136 | uint8_t CC1101::readRegister(uint8_t address, uint8_t registerType) 137 | { 138 | switch (address) 139 | { 140 | case CC1101_FREQEST: 141 | case CC1101_MARCSTATE: 142 | case CC1101_RXBYTES: 143 | case CC1101_TXBYTES: 144 | case CC1101_WORTIME1: 145 | case CC1101_WORTIME0: 146 | return readRegisterWithSyncProblem(address, registerType); 147 | 148 | default: 149 | return readRegister(address | registerType); 150 | } 151 | } 152 | 153 | void CC1101::writeBurstRegister(uint8_t address, uint8_t* data, uint8_t length) 154 | { 155 | uint8_t i; 156 | 157 | select(); 158 | spi_waitMiso(); 159 | SPI.transfer(address | CC1101_WRITE_BURST); 160 | for (i = 0; i < length; i++) { 161 | SPI.transfer(data[i]); 162 | } 163 | deselect(); 164 | } 165 | 166 | void CC1101::readBurstRegister(uint8_t* buffer, uint8_t address, uint8_t length) 167 | { 168 | uint8_t i; 169 | 170 | select(); 171 | spi_waitMiso(); 172 | SPI.transfer(address | CC1101_READ_BURST); 173 | 174 | for (i = 0; i < length; i++) { 175 | buffer[i] = SPI.transfer(0x00); 176 | } 177 | 178 | deselect(); 179 | } 180 | 181 | //wait for fixed length in rx fifo 182 | uint8_t CC1101::receiveData(CC1101Packet* packet, uint8_t length) 183 | { 184 | uint8_t rxBytes = readRegisterWithSyncProblem(CC1101_RXBYTES, CC1101_STATUS_REGISTER); 185 | rxBytes = rxBytes & CC1101_BITS_RX_BYTES_IN_FIFO; 186 | 187 | //check for rx fifo overflow 188 | if ((readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE) == CC1101_MARCSTATE_RXFIFO_OVERFLOW) 189 | { 190 | writeCommand(CC1101_SIDLE); //idle 191 | writeCommand(CC1101_SFRX); //flush RX buffer 192 | writeCommand(CC1101_SRX); //switch to RX state 193 | } 194 | else if (rxBytes == length) 195 | { 196 | readBurstRegister(packet->data, CC1101_RXFIFO, rxBytes); 197 | 198 | //continue RX 199 | writeCommand(CC1101_SIDLE); //idle 200 | writeCommand(CC1101_SFRX); //flush RX buffer 201 | writeCommand(CC1101_SRX); //switch to RX state 202 | 203 | packet->length = rxBytes; 204 | } 205 | else 206 | { 207 | //empty fifo 208 | packet->length = 0; 209 | } 210 | 211 | return packet->length; 212 | } 213 | 214 | //This function is able to send packets bigger then the FIFO size. 215 | void CC1101::sendData(CC1101Packet *packet) 216 | { 217 | uint8_t index = 0; 218 | uint8_t txStatus, MarcState; 219 | uint8_t length; 220 | 221 | writeCommand(CC1101_SIDLE); //idle 222 | 223 | txStatus = readRegisterWithSyncProblem(CC1101_TXBYTES, CC1101_STATUS_REGISTER); 224 | 225 | //clear TX fifo if needed 226 | if (txStatus & CC1101_BITS_TX_FIFO_UNDERFLOW) 227 | { 228 | writeCommand(CC1101_SIDLE); //idle 229 | writeCommand(CC1101_SFTX); //flush TX buffer 230 | } 231 | 232 | writeCommand(CC1101_SIDLE); //idle 233 | 234 | //determine how many bytes to send 235 | length = (packet->length <= CC1101_DATA_LEN ? packet->length : CC1101_DATA_LEN); 236 | 237 | writeBurstRegister(CC1101_TXFIFO, packet->data, length); 238 | 239 | writeCommand(CC1101_SIDLE); 240 | //start sending packet 241 | writeCommand(CC1101_STX); 242 | 243 | //continue sending when packet is bigger than 64 bytes 244 | if (packet->length > CC1101_DATA_LEN) 245 | { 246 | index += length; 247 | 248 | //loop until all bytes are transmitted 249 | while (index < packet->length) 250 | { 251 | //check if there is free space in the fifo 252 | while ((txStatus = (readRegisterMedian3(CC1101_TXBYTES | CC1101_STATUS_REGISTER) & CC1101_BITS_RX_BYTES_IN_FIFO)) > (CC1101_DATA_LEN - 2)); 253 | 254 | //calculate how many bytes we can send 255 | length = (CC1101_DATA_LEN - txStatus); 256 | length = ((packet->length - index) < length ? (packet->length - index) : length); 257 | 258 | //send some more bytes 259 | for (int i=0; idata[index+i]); 261 | 262 | index += length; 263 | } 264 | } 265 | 266 | //wait until transmission is finished (TXOFF_MODE is expected to be set to 0/IDLE or TXFIFO_UNDERFLOW) 267 | do 268 | { 269 | MarcState = (readRegisterWithSyncProblem(CC1101_MARCSTATE, CC1101_STATUS_REGISTER) & CC1101_BITS_MARCSTATE); 270 | // if (MarcState == CC1101_MARCSTATE_TXFIFO_UNDERFLOW) Serial.print(F("TXFIFO_UNDERFLOW occured in sendData() \n")); 271 | } 272 | while((MarcState != CC1101_MARCSTATE_IDLE) && (MarcState != CC1101_MARCSTATE_TXFIFO_UNDERFLOW)); 273 | } 274 | -------------------------------------------------------------------------------- /libraries _PLUGIN145 ITHO FAN/Itho/CC1101Packet.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef CC1101PACKET_H_ 6 | #define CC1101PACKET_H_ 7 | 8 | #include 9 | #ifdef ESP8266 10 | #include 11 | #endif 12 | 13 | #define CC1101_BUFFER_LEN 64 14 | #define CC1101_DATA_LEN CC1101_BUFFER_LEN - 3 15 | 16 | 17 | class CC1101Packet 18 | { 19 | public: 20 | uint8_t length; 21 | uint8_t data[72]; 22 | }; 23 | 24 | 25 | #endif /* CC1101PACKET_H_ */ -------------------------------------------------------------------------------- /libraries _PLUGIN145 ITHO FAN/Itho/IthoCC1101.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/enesbcs/ESPEasyPluginPlayground/0a4399e4342c216a91cb25d6f47e33df96a4beec/libraries _PLUGIN145 ITHO FAN/Itho/IthoCC1101.cpp -------------------------------------------------------------------------------- /libraries _PLUGIN145 ITHO FAN/Itho/IthoCC1101.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef __ITHOCC1101_H__ 6 | #define __ITHOCC1101_H__ 7 | 8 | #include 9 | #include "CC1101.h" 10 | #include "IthoPacket.h" 11 | 12 | 13 | //pa table settings 14 | const uint8_t ithoPaTableSend[8] = {0x6F, 0x26, 0x2E, 0x8C, 0x87, 0xCD, 0xC7, 0xC0}; 15 | const uint8_t ithoPaTableReceive[8] = {0x6F, 0x26, 0x2E, 0x7F, 0x8A, 0x84, 0xCA, 0xC4}; 16 | 17 | //rft message 1 commands 18 | const uint8_t ithoMessage1HighCommandBytes[] = {1,84,213,85,50,203,52}; 19 | const uint8_t ithoMessage1MediumCommandBytes[] = {1,84,213,85,74,213,52}; 20 | const uint8_t ithoMessage1LowCommandBytes[] = {1,84,213,85,83,83,84}; 21 | const uint8_t ithoMessage1Timer1CommandBytes[] = {1,83,83,84,204,202,180}; 22 | const uint8_t ithoMessage1Timer2CommandBytes[] = {1,83,83,83,53,52,180}; 23 | const uint8_t ithoMessage1Timer3CommandBytes[] = {1,83,83,82,173,82,180}; 24 | const uint8_t ithoMessage1JoinCommandBytes[] = {0,170,171,85,84,202,180}; 25 | const uint8_t ithoMessage1LeaveCommandBytes[] = {0,170,173,85,83,43,84}; 26 | 27 | //duco message1 commands 28 | const uint8_t ducoMessage1HighCommandBytes[] = {1,84,213,85,51,45,52}; 29 | const uint8_t ducoMessage1MediumCommandBytes[] = {1,84,213,85,75,51,52}; 30 | const uint8_t ducoMessage1LowCommandBytes[] = {1,84,213,85,82,181,84}; 31 | const uint8_t ducoMessage1StandByCommandBytes[] = {1,85,53,84,205,85,52}; 32 | const uint8_t ducoMessage1JoinCommandBytes[] = {0,170,171,85,85,44,180}; 33 | const uint8_t ducoMessage1LeaveCommandBytes[] = {0,170,173,85,82,205,84}; 34 | 35 | //message 2 commands 36 | const uint8_t ithoMessage2PowerCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,102,85,150}; 37 | const uint8_t ithoMessage2HighCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,89,102,85,150}; 38 | const uint8_t ithoMessage2MediumCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,150,85,150}; 39 | const uint8_t ithoMessage2LowCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,89,150,85,150}; 40 | const uint8_t ithoMessage2StandByCommandBytes[] = {6,89,150,170,165,101,90,150,85,149,101,90,86,85,150}; 41 | const uint8_t ithoMessage2Timer1CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,85,153}; //10 minutes full speed 42 | const uint8_t ithoMessage2Timer2CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,149,150}; //20 minutes full speed 43 | const uint8_t ithoMessage2Timer3CommandBytes[] = {6,89,150,170,169,101,90,150,85,149,101,89,86,149,154}; //30 minutes full speed 44 | const uint8_t ithoMessage2JoinCommandBytes[] = {9,90,170,90,165,165,89,106,85,149,102,89,150,170,165}; 45 | const uint8_t ithoMessage2LeaveCommandBytes[] = {9,90,170,90,165,165,89,166,85,149,105,90,170,90,165}; 46 | 47 | //message 2, counter 48 | const uint8_t counterBytes24a[] = {1,2}; 49 | const uint8_t counterBytes24b[] = {84,148,100,164,88,152,104,168}; 50 | const uint8_t counterBytes25[] = {149,165,153,169,150,166,154,170}; 51 | const uint8_t counterBytes26[] = {96,160}; 52 | const uint8_t counterBytes41[] = {5, 10, 6, 9}; 53 | const uint8_t counterBytes42[] = {90, 170, 106, 154}; 54 | const uint8_t counterBytes43[] = {154, 90, 166, 102, 150, 86, 170, 106}; 55 | //join/leave 56 | const uint8_t counterBytes64[] = {154,90,166,102,150,86,169,105,153,89,165,101,149,85,170,106}; 57 | const uint8_t counterBytes65[] = {150,169,153,165,149,170,154,166}; 58 | const uint8_t counterBytes66[] = {170,106}; 59 | 60 | 61 | //state machine 62 | typedef enum IthoReceiveStates 63 | { 64 | ExpectMessageStart, 65 | ExpectNormalCommand, 66 | ExpectJoinCommand, 67 | ExpectLeaveCommand 68 | }; 69 | 70 | 71 | 72 | class IthoCC1101 : protected CC1101 73 | { 74 | private: 75 | //receive 76 | IthoReceiveStates receiveState; //state machine receive 77 | unsigned long lastMessage1Received; //used for timeout detection 78 | CC1101Packet inMessage1; //temp storage message1 79 | CC1101Packet inMessage2; //temp storage message2 80 | IthoPacket inIthoPacket; //stores last received message data 81 | 82 | //send 83 | IthoPacket outIthoPacket; //stores state of "remote" 84 | 85 | //settings 86 | uint8_t sendTries; //number of times a command is send at one button press 87 | 88 | //functions 89 | public: 90 | IthoCC1101(uint8_t counter = 0, uint8_t sendTries = 3); //set initial counter value 91 | ~IthoCC1101(); 92 | 93 | //init 94 | void init() { CC1101::init(); } //init,reset CC1101 95 | void initReceive(); 96 | uint8_t getLastCounter() { return outIthoPacket.counter; } //counter is increased before sending a command 97 | void setSendTries(uint8_t sendTries) { this->sendTries = sendTries; } 98 | 99 | //- deviceid should be a setting as well? random gen function? TODO 100 | 101 | //receive 102 | bool checkForNewPacket(); //check RX fifo for new data 103 | IthoPacket getLastPacket() { return inIthoPacket; } //retrieve last received/parsed packet from remote 104 | IthoCommand getLastCommand() { return inIthoPacket.command; } //retrieve last received/parsed command from remote 105 | uint8_t getLastInCounter() { return inIthoPacket.counter; } //retrieve last received/parsed command from remote 106 | uint8_t ReadRSSI(); 107 | bool checkID(const uint8_t *id); 108 | String getLastIDstr(); 109 | 110 | //send 111 | void sendCommand(IthoCommand command); 112 | protected: 113 | private: 114 | IthoCC1101( const IthoCC1101 &c); 115 | IthoCC1101& operator=( const IthoCC1101 &c); 116 | 117 | //init CC1101 for receiving 118 | void initReceiveMessage1(); 119 | void initReceiveMessage2(IthoMessageType expectedMessageType); 120 | 121 | //init CC1101 for sending 122 | void initSendMessage1(); 123 | void initSendMessage2(IthoCommand command); 124 | void finishTransfer(); 125 | 126 | //receive message validation 127 | bool isValidMessageStart(); 128 | bool isValidMessageCommand(); 129 | bool isValidMessageJoin(); 130 | bool isValidMessageLeave(); 131 | 132 | //parse received message 133 | void parseReceivedPackets(); 134 | void parseMessageStart(); 135 | void parseMessageCommand(); 136 | void parseMessageJoin(); 137 | void parseMessageLeave(); 138 | 139 | //send 140 | void createMessageStart(IthoPacket *itho, CC1101Packet *packet); 141 | void createMessageCommand(IthoPacket *itho, CC1101Packet *packet); 142 | void createMessageJoin(IthoPacket *itho, CC1101Packet *packet); 143 | void createMessageLeave(IthoPacket *itho, CC1101Packet *packet); 144 | uint8_t* getMessage1CommandBytes(IthoCommand command); 145 | uint8_t* getMessage2CommandBytes(IthoCommand command); 146 | 147 | //counter bytes calculation (send) 148 | uint8_t getMessage1Byte18(IthoCommand command); 149 | IthoCommand getMessage1PreviousCommand(uint8_t byte18); 150 | uint8_t calculateMessage2Byte24(uint8_t counter); 151 | uint8_t calculateMessage2Byte25(uint8_t counter); 152 | uint8_t calculateMessage2Byte26(uint8_t counter); 153 | uint8_t calculateMessage2Byte41(uint8_t counter, IthoCommand command); 154 | uint8_t calculateMessage2Byte42(uint8_t counter, IthoCommand command); 155 | uint8_t calculateMessage2Byte43(uint8_t counter, IthoCommand command); 156 | uint8_t calculateMessage2Byte49(uint8_t counter); 157 | uint8_t calculateMessage2Byte50(uint8_t counter); 158 | uint8_t calculateMessage2Byte51(uint8_t counter); 159 | uint8_t calculateMessage2Byte64(uint8_t counter); 160 | uint8_t calculateMessage2Byte65(uint8_t counter); 161 | uint8_t calculateMessage2Byte66(uint8_t counter); 162 | 163 | //counter calculation (receive) 164 | uint8_t calculateMessageCounter(uint8_t byte24, uint8_t byte25, uint8_t byte26); 165 | 166 | //general 167 | uint8_t getCounterIndex(const uint8_t *arr, uint8_t length, uint8_t value); 168 | 169 | //test 170 | void testCreateMessage(); 171 | 172 | }; //IthoCC1101 173 | 174 | 175 | extern volatile uint32_t data1[]; 176 | 177 | #endif //__ITHOCC1101_H__ 178 | -------------------------------------------------------------------------------- /libraries _PLUGIN145 ITHO FAN/Itho/IthoPacket.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Klusjesman, modified bij supersjimmie for Arduino/ESP8266 3 | */ 4 | 5 | #ifndef ITHOPACKET_H_ 6 | #define ITHOPACKET_H_ 7 | 8 | 9 | typedef enum IthoMessageType 10 | { 11 | ithomsg_unknown = 0, 12 | ithomsg_control = 1, 13 | ithomsg_join = 2, 14 | ithomsg_leave = 3 15 | }; 16 | 17 | //do not change enum because they are used in calculations! 18 | enum IthoCommand 19 | { 20 | IthoUnknown = 0, 21 | 22 | IthoJoin = 4, 23 | IthoLeave = 8, 24 | 25 | IthoStandby = 34, 26 | IthoLow = 35, 27 | IthoMedium = 36, 28 | IthoHigh = 37, 29 | IthoFull = 38, 30 | 31 | IthoTimer1 = 41, 32 | IthoTimer2 = 51, 33 | IthoTimer3 = 61, 34 | 35 | //duco c system remote 36 | DucoStandby = 251, 37 | DucoLow = 252, 38 | DucoMedium = 253, 39 | DucoHigh = 254 40 | }; 41 | 42 | 43 | class IthoPacket 44 | { 45 | public: 46 | uint8_t deviceId1[6]; 47 | uint8_t deviceId2[8]; 48 | IthoMessageType messageType; 49 | IthoCommand command; 50 | IthoCommand previous; 51 | 52 | uint8_t counter; //0-255, counter is increased on every remote button press 53 | }; 54 | 55 | 56 | #endif /* ITHOPACKET_H_ */ --------------------------------------------------------------------------------