├── License.txt ├── README.md ├── Serial.ino ├── _P029_Output.ino ├── _P002_ADC.ino ├── Hardware.ino ├── _P018_Dust.ino ├── _P016_IR.ino ├── _P007_PCF8591.ino ├── __CPlugin.ino ├── _P026_Sysinfo.ino ├── _C003.ino ├── _C010.ino ├── _P035_IRTX.ino ├── _C006.ino ├── _P033_Dummy.ino ├── _C005.ino ├── _C004.ino ├── _P034_DHT12.ino ├── _P022_PCA9685.ino ├── _P010_BH1750.ino ├── _P008_RFID.ino ├── _P024_MLX90614.ino ├── _P021_Level.ino ├── _C008.ino ├── _C007.ino ├── Wifi.ino ├── Controller.ino ├── _P013_HCSR04.ino ├── _C009.ino ├── _P025_ADS1115.ino ├── _P005_DHT.ino ├── _P031_SHT1X.ino ├── _P019_PCF8574.ino ├── _P011_PME.ino ├── _C001.ino ├── _P012_LCD.ino ├── _C002.ino ├── _P003_Pulse.ino ├── _P032_MS5611.ino └── _P006_BMP085.ino /License.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zen/ESPEasy/master/License.txt -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPEasy 2 | Easy MultiSensor device based on ESP8266 3 | 4 | This is where development takes place. Beware that latest versions may be unstable. 5 | 6 | Stable versions including libraries are currently on SoureForge: 7 | 8 | http://sourceforge.net/projects/espeasy/ 9 | 10 | Wiki: http://www.esp8266.nu 11 | Forum: http://www.esp8266.nu/forum 12 | -------------------------------------------------------------------------------- /Serial.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************************************\ 2 | * Get data from Serial Interface 3 | \*********************************************************************************************/ 4 | #define INPUT_BUFFER_SIZE 128 5 | 6 | byte SerialInByte; 7 | int SerialInByteCounter = 0; 8 | char InputBuffer_Serial[INPUT_BUFFER_SIZE + 2]; 9 | 10 | void serial() 11 | { 12 | while (Serial.available()) 13 | { 14 | yield(); 15 | SerialInByte = Serial.read(); 16 | if (SerialInByte == 255) // binary data... 17 | { 18 | Serial.flush(); 19 | return; 20 | } 21 | 22 | if (isprint(SerialInByte)) 23 | { 24 | if (SerialInByteCounter < INPUT_BUFFER_SIZE) // add char to string if it still fits 25 | InputBuffer_Serial[SerialInByteCounter++] = SerialInByte; 26 | } 27 | 28 | if (SerialInByte == '\n') 29 | { 30 | InputBuffer_Serial[SerialInByteCounter] = 0; // serial data completed 31 | Serial.write('>'); 32 | Serial.println(InputBuffer_Serial); 33 | String action = InputBuffer_Serial; 34 | struct EventStruct TempEvent; 35 | parseCommandString(&TempEvent, action); 36 | TempEvent.Source = VALUE_SOURCE_SERIAL; 37 | if (!PluginCall(PLUGIN_WRITE, &TempEvent, action)) 38 | ExecuteCommand(VALUE_SOURCE_SERIAL, InputBuffer_Serial); 39 | SerialInByteCounter = 0; 40 | InputBuffer_Serial[0] = 0; // serial data processed, clear buffer 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /_P029_Output.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 029: Output ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_029 6 | #define PLUGIN_ID_029 29 7 | #define PLUGIN_NAME_029 "Output - (Domoticz MQTT helper)" 8 | #define PLUGIN_VALUENAME1_029 "Output" 9 | boolean Plugin_029(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_029; 19 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 20 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = false; 25 | Device[deviceCount].ValueCount = 1; 26 | Device[deviceCount].SendDataOption = false; 27 | break; 28 | } 29 | 30 | case PLUGIN_GET_DEVICENAME: 31 | { 32 | string = F(PLUGIN_NAME_029); 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICEVALUENAMES: 37 | { 38 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_029)); 39 | break; 40 | } 41 | 42 | case PLUGIN_INIT: 43 | { 44 | success = true; 45 | break; 46 | } 47 | } 48 | return success; 49 | } 50 | -------------------------------------------------------------------------------- /_P002_ADC.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 002: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_002 6 | #define PLUGIN_ID_002 2 7 | #define PLUGIN_NAME_002 "Analog input" 8 | #define PLUGIN_VALUENAME1_002 "Analog" 9 | boolean Plugin_002(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_002; 19 | Device[deviceCount].Type = DEVICE_TYPE_ANALOG; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = true; 25 | Device[deviceCount].ValueCount = 1; 26 | Device[deviceCount].SendDataOption = true; 27 | Device[deviceCount].TimerOption = true; 28 | Device[deviceCount].GlobalSyncOption = true; 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICENAME: 33 | { 34 | string = F(PLUGIN_NAME_002); 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICEVALUENAMES: 39 | { 40 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_002)); 41 | break; 42 | } 43 | 44 | case PLUGIN_READ: 45 | { 46 | int value = analogRead(A0); 47 | UserVar[event->BaseVarIndex] = (float)value; 48 | String log = F("ADC : Analog value: "); 49 | log += value; 50 | addLog(LOG_LEVEL_INFO,log); 51 | success = true; 52 | break; 53 | } 54 | } 55 | return success; 56 | } 57 | -------------------------------------------------------------------------------- /Hardware.ino: -------------------------------------------------------------------------------- 1 | /********************************************************************************************\ 2 | * Initialize specific hardware setings (only global ones, others are set through devices) 3 | \*********************************************************************************************/ 4 | 5 | void hardwareInit() 6 | { 7 | 8 | // set GPIO pins state if not set to default 9 | for (byte x=0; x < 17; x++) 10 | if (Settings.PinBootStates[x] != 0) 11 | switch(Settings.PinBootStates[x]) 12 | { 13 | case 1: 14 | pinMode(x,OUTPUT); 15 | digitalWrite(x,LOW); 16 | setPinState(1, x, PIN_MODE_OUTPUT, LOW); 17 | break; 18 | case 2: 19 | pinMode(x,OUTPUT); 20 | digitalWrite(x,HIGH); 21 | setPinState(1, x, PIN_MODE_OUTPUT, HIGH); 22 | break; 23 | case 3: 24 | pinMode(x,INPUT_PULLUP); 25 | setPinState(1, x, PIN_MODE_INPUT, 0); 26 | break; 27 | } 28 | 29 | // configure hardware pins according to eeprom settings. 30 | if (Settings.Pin_i2c_sda != -1) 31 | { 32 | String log = F("INIT : I2C"); 33 | addLog(LOG_LEVEL_INFO, log); 34 | Wire.begin(Settings.Pin_i2c_sda, Settings.Pin_i2c_scl); 35 | if(Settings.WireClockStretchLimit) 36 | { 37 | String log = F("INIT : I2C custom clockstretchlimit:"); 38 | log += Settings.WireClockStretchLimit; 39 | addLog(LOG_LEVEL_INFO, log); 40 | Wire.setClockStretchLimit(Settings.WireClockStretchLimit); 41 | } 42 | } 43 | 44 | // I2C Watchdog boot status check 45 | if (Settings.WDI2CAddress != 0) 46 | { 47 | delay(500); 48 | Wire.beginTransmission(Settings.WDI2CAddress); 49 | Wire.write(0x83); // command to set pointer 50 | Wire.write(17); // pointer value to status byte 51 | Wire.endTransmission(); 52 | 53 | Wire.requestFrom(Settings.WDI2CAddress, (uint8_t)1); 54 | if (Wire.available()) 55 | { 56 | byte status = Wire.read(); 57 | if (status & 0x1) 58 | { 59 | String log = F("INIT : Reset by WD!"); 60 | addLog(LOG_LEVEL_ERROR, log); 61 | lastBootCause = BOOT_CAUSE_EXT_WD; 62 | } 63 | } 64 | } 65 | 66 | // SPI Init 67 | if (Settings.InitSPI) 68 | { 69 | SPI.setHwCs(false); 70 | SPI.begin(); 71 | addLog(LOG_LEVEL_INFO, (char*)"INIT : SPI Init (without CS)"); 72 | } 73 | else 74 | { 75 | addLog(LOG_LEVEL_INFO, (char*)"INIT : SPI not enabled"); 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /_P018_Dust.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 018: GP2Y10 ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_018 6 | #define PLUGIN_ID_018 18 7 | #define PLUGIN_NAME_018 "Dust Sensor - Sharp GP2Y10" 8 | #define PLUGIN_VALUENAME1_018 "Dust" 9 | 10 | boolean Plugin_018_init = false; 11 | byte Plugin_GP2Y10_LED_Pin = 0; 12 | 13 | boolean Plugin_018(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_018; 22 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 23 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 24 | Device[deviceCount].Ports = 0; 25 | Device[deviceCount].PullUpOption = false; 26 | Device[deviceCount].InverseLogicOption = false; 27 | Device[deviceCount].FormulaOption = true; 28 | Device[deviceCount].ValueCount = 1; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_018); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_018)); 44 | break; 45 | } 46 | 47 | case PLUGIN_INIT: 48 | { 49 | Plugin_018_init = true; 50 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 51 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 52 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 53 | success = true; 54 | break; 55 | } 56 | 57 | 58 | case PLUGIN_READ: 59 | { 60 | Plugin_GP2Y10_LED_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 61 | noInterrupts(); 62 | byte x; 63 | int value; 64 | value = 0; 65 | for (x = 0; x < 25; x++) 66 | { 67 | digitalWrite(Plugin_GP2Y10_LED_Pin, LOW); 68 | delayMicroseconds(280); 69 | value = value + analogRead(A0); 70 | delayMicroseconds(40); 71 | digitalWrite(Plugin_GP2Y10_LED_Pin, HIGH); 72 | delayMicroseconds(9680); 73 | } 74 | interrupts(); 75 | UserVar[event->BaseVarIndex] = (float)value; 76 | String log = F("GPY : Dust value: "); 77 | log += value; 78 | addLog(LOG_LEVEL_INFO, log); 79 | success = true; 80 | break; 81 | } 82 | } 83 | return success; 84 | } 85 | -------------------------------------------------------------------------------- /_P016_IR.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 016: Input IR ############################################# 3 | //####################################################################################################### 4 | 5 | #include 6 | IRrecv *irReceiver; 7 | decode_results results; 8 | 9 | #define PLUGIN_016 10 | #define PLUGIN_ID_016 16 11 | #define PLUGIN_NAME_016 "Infrared Receive - TSOP4838" 12 | #define PLUGIN_VALUENAME1_016 "IR" 13 | 14 | boolean Plugin_016(byte function, struct EventStruct *event, String& string) 15 | { 16 | boolean success = false; 17 | 18 | switch (function) 19 | { 20 | case PLUGIN_DEVICE_ADD: 21 | { 22 | Device[++deviceCount].Number = PLUGIN_ID_016; 23 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 24 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 25 | Device[deviceCount].Ports = 0; 26 | Device[deviceCount].PullUpOption = true; 27 | Device[deviceCount].InverseLogicOption = true; 28 | Device[deviceCount].FormulaOption = false; 29 | Device[deviceCount].ValueCount = 1; 30 | Device[deviceCount].SendDataOption = true; 31 | Device[deviceCount].TimerOption = false; 32 | Device[deviceCount].GlobalSyncOption = true; 33 | break; 34 | } 35 | 36 | case PLUGIN_GET_DEVICENAME: 37 | { 38 | string = F(PLUGIN_NAME_016); 39 | break; 40 | } 41 | 42 | case PLUGIN_GET_DEVICEVALUENAMES: 43 | { 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_016)); 45 | break; 46 | } 47 | 48 | case PLUGIN_INIT: 49 | { 50 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 51 | if (irReceiver == 0 && irPin != -1) 52 | { 53 | Serial.println("IR Init"); 54 | irReceiver= new IRrecv(irPin); 55 | irReceiver->enableIRIn(); // Start the receiver 56 | } 57 | if (irReceiver != 0 && irPin == -1) 58 | { 59 | Serial.println("IR Removed"); 60 | irReceiver->disableIRIn(); 61 | delete irReceiver; 62 | irReceiver=0; 63 | } 64 | success = true; 65 | break; 66 | } 67 | 68 | case PLUGIN_TEN_PER_SECOND: 69 | { 70 | if (irReceiver->decode(&results)) 71 | { 72 | unsigned long IRcode = results.value; 73 | irReceiver->resume(); 74 | UserVar[event->BaseVarIndex] = (IRcode & 0xFFFF); 75 | UserVar[event->BaseVarIndex + 1] = ((IRcode >> 16) & 0xFFFF); 76 | String log = F("IR : Code "); 77 | log += String(IRcode, HEX); 78 | addLog(LOG_LEVEL_INFO, log); 79 | sendData(event); 80 | } 81 | success = true; 82 | break; 83 | } 84 | } 85 | return success; 86 | } 87 | 88 | -------------------------------------------------------------------------------- /_P007_PCF8591.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 007: ExtWiredAnalog ####################################### 3 | //####################################################################################################### 4 | 5 | /*********************************************************************************************\ 6 | * This plugin provides support for 4 extra analog inputs, using the PCF8591 (NXP/Philips) 7 | * Support : www.esp8266.nu 8 | * Date : Apr 2015 9 | * Compatibility : R004 10 | * Syntax : "ExtWiredAnalog , " 11 | ********************************************************************************************* 12 | * Technical description: 13 | * 14 | * The PCF8591 is a IO Expander chip that connects through the I2C bus 15 | * Basic I2C address = 0x48 16 | * Each chip has 4 analog inputs 17 | * This commando reads the analog input and stores the result into a variable 18 | \*********************************************************************************************/ 19 | #define PLUGIN_007 20 | #define PLUGIN_ID_007 7 21 | #define PLUGIN_NAME_007 "Analog input - PCF8591" 22 | #define PLUGIN_VALUENAME1_007 "Analog" 23 | 24 | boolean Plugin_007(byte function, struct EventStruct *event, String& string) 25 | { 26 | boolean success = false; 27 | 28 | static byte portValue = 0; 29 | 30 | switch (function) 31 | { 32 | case PLUGIN_DEVICE_ADD: 33 | { 34 | Device[++deviceCount].Number = PLUGIN_ID_007; 35 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 36 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 37 | Device[deviceCount].Ports = 4; 38 | Device[deviceCount].PullUpOption = false; 39 | Device[deviceCount].InverseLogicOption = false; 40 | Device[deviceCount].FormulaOption = true; 41 | Device[deviceCount].ValueCount = 1; 42 | Device[deviceCount].SendDataOption = true; 43 | Device[deviceCount].TimerOption = true; 44 | Device[deviceCount].GlobalSyncOption = true; 45 | break; 46 | } 47 | 48 | case PLUGIN_GET_DEVICENAME: 49 | { 50 | string = F(PLUGIN_NAME_007); 51 | break; 52 | } 53 | 54 | case PLUGIN_GET_DEVICEVALUENAMES: 55 | { 56 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_007)); 57 | break; 58 | } 59 | 60 | case PLUGIN_READ: 61 | { 62 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 63 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 64 | uint8_t address = 0x48 + unit; 65 | 66 | // get the current pin value 67 | Wire.beginTransmission(address); 68 | Wire.write(port - 1); 69 | Wire.endTransmission(); 70 | 71 | Wire.requestFrom(address, (uint8_t)0x2); 72 | if (Wire.available()) 73 | { 74 | Wire.read(); // Read older value first (stored in chip) 75 | UserVar[event->BaseVarIndex] = (float)Wire.read(); // now read actual value and store into Nodo var 76 | String log = F("PCF : Analog value: "); 77 | log += UserVar[event->BaseVarIndex]; 78 | addLog(LOG_LEVEL_INFO,log); 79 | success = true; 80 | } 81 | break; 82 | } 83 | } 84 | return success; 85 | } 86 | 87 | -------------------------------------------------------------------------------- /__CPlugin.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Initialize all Controller CPlugins that where defined earlier 3 | // and initialize the function call pointer into the CCPlugin array 4 | //******************************************************************************** 5 | void CPluginInit(void) 6 | { 7 | byte x; 8 | 9 | // Clear pointer table for all plugins 10 | for (x = 0; x < CPLUGIN_MAX; x++) 11 | { 12 | CPlugin_ptr[x] = 0; 13 | CPlugin_id[x] = 0; 14 | } 15 | 16 | x = 0; 17 | 18 | #ifdef CPLUGIN_001 19 | CPlugin_id[x] = 1; CPlugin_ptr[x++] = &CPlugin_001; 20 | #endif 21 | 22 | #ifdef CPLUGIN_002 23 | CPlugin_id[x] = 2; CPlugin_ptr[x++] = &CPlugin_002; 24 | #endif 25 | 26 | #ifdef CPLUGIN_003 27 | CPlugin_id[x] = 3; CPlugin_ptr[x++] = &CPlugin_003; 28 | #endif 29 | 30 | #ifdef CPLUGIN_004 31 | CPlugin_id[x] = 4; CPlugin_ptr[x++] = &CPlugin_004; 32 | #endif 33 | 34 | #ifdef CPLUGIN_005 35 | CPlugin_id[x] = 5; CPlugin_ptr[x++] = &CPlugin_005; 36 | #endif 37 | 38 | #ifdef CPLUGIN_006 39 | CPlugin_id[x] = 6; CPlugin_ptr[x++] = &CPlugin_006; 40 | #endif 41 | 42 | #ifdef CPLUGIN_007 43 | CPlugin_id[x] = 7; CPlugin_ptr[x++] = &CPlugin_007; 44 | #endif 45 | 46 | #ifdef CPLUGIN_008 47 | CPlugin_id[x] = 8; CPlugin_ptr[x++] = &CPlugin_008; 48 | #endif 49 | 50 | #ifdef CPLUGIN_009 51 | CPlugin_id[x] = 9; CPlugin_ptr[x++] = &CPlugin_009; 52 | #endif 53 | 54 | #ifdef CPLUGIN_010 55 | CPlugin_id[x] = 10; CPlugin_ptr[x++] = &CPlugin_010; 56 | #endif 57 | 58 | #ifdef CPLUGIN_011 59 | CPlugin_id[x] = 11; CPlugin_ptr[x++] = &CPlugin_011; 60 | #endif 61 | 62 | #ifdef CPLUGIN_012 63 | CPlugin_id[x] = 12; CPlugin_ptr[x++] = &CPlugin_012; 64 | #endif 65 | 66 | #ifdef CPLUGIN_013 67 | CPlugin_id[x] = 13; CPlugin_ptr[x++] = &CPlugin_013; 68 | #endif 69 | 70 | #ifdef CPLUGIN_014 71 | CPlugin_id[x] = 14; CPlugin_ptr[x++] = &CPlugin_014; 72 | #endif 73 | 74 | #ifdef CPLUGIN_015 75 | CPlugin_id[x] = 15; CPlugin_ptr[x++] = &CPlugin_015; 76 | #endif 77 | 78 | #ifdef CPLUGIN_016 79 | CPlugin_id[x] = 16; CPlugin_ptr[x++] = &CPlugin_016; 80 | #endif 81 | 82 | #ifdef CPLUGIN_017 83 | CPlugin_id[x] = 17; CPlugin_ptr[x++] = &CPlugin_017; 84 | #endif 85 | 86 | #ifdef CPLUGIN_018 87 | CPlugin_id[x] = 18; CPlugin_ptr[x++] = &CPlugin_018; 88 | #endif 89 | 90 | #ifdef CPLUGIN_019 91 | CPlugin_id[x] = 19; CPlugin_ptr[x++] = &CPlugin_019; 92 | #endif 93 | 94 | #ifdef CPLUGIN_020 95 | CPlugin_id[x] = 20; CPlugin_ptr[x++] = &CPlugin_020; 96 | #endif 97 | 98 | #ifdef CPLUGIN_021 99 | CPlugin_id[x] = 21; CPlugin_ptr[x++] = &CPlugin_021; 100 | #endif 101 | 102 | #ifdef CPLUGIN_022 103 | CPlugin_id[x] = 22; CPlugin_ptr[x++] = &CPlugin_022; 104 | #endif 105 | 106 | #ifdef CPLUGIN_023 107 | CPlugin_id[x] = 23; CPlugin_ptr[x++] = &CPlugin_023; 108 | #endif 109 | 110 | #ifdef CPLUGIN_024 111 | CPlugin_id[x] = 24; CPlugin_ptr[x++] = &CPlugin_024; 112 | #endif 113 | 114 | #ifdef CPLUGIN_025 115 | CPlugin_id[x] = 25; CPlugin_ptr[x++] = &CPlugin_025; 116 | #endif 117 | 118 | CPluginCall(CPLUGIN_PROTOCOL_ADD, 0); 119 | } 120 | 121 | byte CPluginCall(byte Function, struct EventStruct *event) 122 | { 123 | int x; 124 | struct EventStruct TempEvent; 125 | 126 | if (event == 0) 127 | event=&TempEvent; 128 | 129 | switch (Function) 130 | { 131 | // Unconditional calls to all plugins 132 | case CPLUGIN_PROTOCOL_ADD: 133 | for (x = 0; x < CPLUGIN_MAX; x++) 134 | if (CPlugin_id[x] != 0) 135 | CPlugin_ptr[x](Function, event, dummyString); 136 | return true; 137 | break; 138 | } 139 | 140 | return false; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /_P026_Sysinfo.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 026: Analog ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_026 6 | #define PLUGIN_ID_026 26 7 | #define PLUGIN_NAME_026 "System Info" 8 | #define PLUGIN_VALUENAME1_026 "" 9 | 10 | boolean Plugin_026(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | 14 | switch (function) 15 | { 16 | 17 | case PLUGIN_DEVICE_ADD: 18 | { 19 | Device[++deviceCount].Number = PLUGIN_ID_026; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].ValueCount = 1; 22 | Device[deviceCount].SendDataOption = true; 23 | Device[deviceCount].TimerOption = true; 24 | Device[deviceCount].FormulaOption = true; 25 | break; 26 | } 27 | 28 | case PLUGIN_GET_DEVICENAME: 29 | { 30 | string = F(PLUGIN_NAME_026); 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICEVALUENAMES: 35 | { 36 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_026)); 37 | break; 38 | } 39 | 40 | case PLUGIN_WEBFORM_LOAD: 41 | { 42 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 43 | String options[4]; 44 | options[0] = F("Uptime"); 45 | options[1] = F("Free RAM"); 46 | options[2] = F("Wifi RSSI"); 47 | options[3] = F("Input VCC"); 48 | int optionValues[4]; 49 | optionValues[0] = 0; 50 | optionValues[1] = 1; 51 | optionValues[2] = 2; 52 | optionValues[3] = 3; 53 | string += F("Indicator:"); 66 | 67 | success = true; 68 | break; 69 | } 70 | 71 | case PLUGIN_WEBFORM_SAVE: 72 | { 73 | String plugin1 = WebServer.arg("plugin_026"); 74 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 75 | success = true; 76 | break; 77 | } 78 | 79 | case PLUGIN_READ: 80 | { 81 | float value = 0; 82 | switch(Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 83 | { 84 | case 0: 85 | { 86 | value = (wdcounter /2); 87 | break; 88 | } 89 | case 1: 90 | { 91 | value = ESP.getFreeHeap(); 92 | break; 93 | } 94 | case 2: 95 | { 96 | value = WiFi.RSSI(); 97 | break; 98 | } 99 | case 3: 100 | { 101 | #if FEATURE_ADC_VCC 102 | value = vcc; 103 | #else 104 | value = -1.0; 105 | #endif 106 | break; 107 | } 108 | } 109 | UserVar[event->BaseVarIndex] = value; 110 | String log = F("SYS : "); 111 | log += value; 112 | addLog(LOG_LEVEL_INFO,log); 113 | success = true; 114 | break; 115 | } 116 | } 117 | return success; 118 | } 119 | -------------------------------------------------------------------------------- /_C003.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 003: Nodo Telnet ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_003 6 | #define CPLUGIN_ID_003 3 7 | #define CPLUGIN_NAME_003 "Nodo Telnet" 8 | 9 | boolean CPlugin_003(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_003; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 23; 22 | break; 23 | } 24 | 25 | case CPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(CPLUGIN_NAME_003); 28 | break; 29 | } 30 | 31 | case CPLUGIN_PROTOCOL_SEND: 32 | { 33 | char log[80]; 34 | boolean success = false; 35 | char host[20]; 36 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 37 | 38 | sprintf_P(log, PSTR("%s%s using port %u"), "TELNT: connecting to ", host,Settings.ControllerPort); 39 | addLog(LOG_LEVEL_DEBUG, log); 40 | 41 | // Use WiFiClient class to create TCP connections 42 | WiFiClient client; 43 | if (!client.connect(host, Settings.ControllerPort)) 44 | { 45 | connectionFailures++; 46 | strcpy_P(log, PSTR("TELNT: connection failed")); 47 | addLog(LOG_LEVEL_ERROR, log); 48 | return false; 49 | } 50 | statusLED(true); 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | // We now create a URI for the request 55 | String url = F("variableset "); 56 | url += event->idx; 57 | url += ","; 58 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 59 | url += "\n"; 60 | 61 | strcpy_P(log, PSTR("TELNT: Sending enter")); 62 | addLog(LOG_LEVEL_ERROR, log); 63 | client.print(" \n"); 64 | 65 | unsigned long timer = millis() + 200; 66 | while (!client.available() && millis() < timer) 67 | delay(1); 68 | 69 | timer = millis() + 1000; 70 | while (client.available() && millis() < timer && !success) 71 | { 72 | String line = client.readStringUntil('\n'); 73 | if (line.substring(0, 20) == "Enter your password:") 74 | { 75 | success = true; 76 | strcpy_P(log, PSTR("TELNT: Password request ok")); 77 | addLog(LOG_LEVEL_ERROR, log); 78 | } 79 | delay(1); 80 | } 81 | 82 | strcpy_P(log, PSTR("TELNT: Sending pw")); 83 | addLog(LOG_LEVEL_ERROR, log); 84 | client.println(SecuritySettings.ControllerPassword); 85 | delay(100); 86 | while (client.available()) 87 | client.read(); 88 | 89 | strcpy_P(log, PSTR("TELNT: Sending cmd")); 90 | addLog(LOG_LEVEL_ERROR, log); 91 | client.print(url); 92 | delay(10); 93 | while (client.available()) 94 | client.read(); 95 | 96 | strcpy_P(log, PSTR("TELNT: closing connection")); 97 | addLog(LOG_LEVEL_DEBUG, log); 98 | 99 | client.stop(); 100 | 101 | break; 102 | } 103 | 104 | } 105 | return success; 106 | } 107 | 108 | -------------------------------------------------------------------------------- /_C010.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 010: Generic UDP ######################################## 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_010 6 | #define CPLUGIN_ID_010 10 7 | #define CPLUGIN_NAME_010 "Generic UDP" 8 | 9 | boolean CPlugin_010(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_010; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 514; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_010); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTpublish, PSTR("%sysname%_%tskname%_%valname%=%value%")); 35 | break; 36 | } 37 | 38 | case CPLUGIN_PROTOCOL_SEND: 39 | { 40 | byte valueCount = getValueCountFromSensorType(event->sensorType); 41 | for (byte x = 0; x < valueCount; x++) 42 | { 43 | if (event->sensorType == SENSOR_TYPE_LONG) 44 | C010_Send(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 45 | else 46 | C010_Send(event, x, UserVar[event->BaseVarIndex + x], 0); 47 | if (valueCount > 1) 48 | { 49 | unsigned long timer = millis() + Settings.MessageDelay; 50 | while (millis() < timer) 51 | backgroundtasks(); 52 | } 53 | } 54 | break; 55 | } 56 | 57 | } 58 | return success; 59 | } 60 | 61 | 62 | //******************************************************************************** 63 | // Generic UDP message 64 | //******************************************************************************** 65 | boolean C010_Send(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 66 | { 67 | char log[80]; 68 | boolean success = false; 69 | char host[20]; 70 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 71 | 72 | sprintf_P(log, PSTR("%s%s using port %u"), "UDP : sending to ", host, Settings.ControllerPort); 73 | addLog(LOG_LEVEL_DEBUG, log); 74 | 75 | statusLED(true); 76 | 77 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 78 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 79 | 80 | String msg = ""; 81 | msg += Settings.MQTTpublish; 82 | msg.replace("%sysname%", Settings.Name); 83 | msg.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 84 | msg.replace("%id%", String(event->idx)); 85 | msg.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[varIndex]); 86 | if (longValue) 87 | msg.replace("%value%", String(longValue)); 88 | else 89 | msg.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex])); 90 | 91 | IPAddress IP(Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 92 | portUDP.beginPacket(IP, Settings.ControllerPort); 93 | portUDP.write(msg.c_str()); 94 | portUDP.endPacket(); 95 | 96 | msg.toCharArray(log, 80); 97 | addLog(LOG_LEVEL_DEBUG_MORE, log); 98 | 99 | } 100 | 101 | -------------------------------------------------------------------------------- /_P035_IRTX.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 035: Output IR ############################################ 3 | //####################################################################################################### 4 | 5 | #include 6 | IRsend *Plugin_035_irSender; 7 | 8 | #define PLUGIN_035 9 | #define PLUGIN_ID_035 35 10 | #define PLUGIN_NAME_035 "Infrared Transmit" 11 | 12 | boolean Plugin_035(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_035; 21 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 22 | Device[deviceCount].SendDataOption = false; 23 | break; 24 | } 25 | 26 | case PLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(PLUGIN_NAME_035); 29 | break; 30 | } 31 | 32 | case PLUGIN_GET_DEVICEVALUENAMES: 33 | { 34 | break; 35 | } 36 | 37 | case PLUGIN_INIT: 38 | { 39 | int irPin = Settings.TaskDevicePin1[event->TaskIndex]; 40 | if (Plugin_035_irSender == 0 && irPin != -1) 41 | { 42 | addLog(LOG_LEVEL_INFO, "INIT: IR TX"); 43 | Plugin_035_irSender = new IRsend(irPin); 44 | Plugin_035_irSender->begin(); // Start the sender 45 | } 46 | if (Plugin_035_irSender != 0 && irPin == -1) 47 | { 48 | addLog(LOG_LEVEL_INFO, "INIT: IR TX Removed"); 49 | delete Plugin_035_irSender; 50 | Plugin_035_irSender = 0; 51 | } 52 | success = true; 53 | break; 54 | } 55 | 56 | case PLUGIN_WRITE: 57 | { 58 | String IrType; 59 | unsigned long IrCode; 60 | unsigned int IrBits; 61 | char command[80]; 62 | command[0] = 0; 63 | char TmpStr1[80]; 64 | TmpStr1[0] = 0; 65 | string.toCharArray(command, 80); 66 | 67 | String tmpString = string; 68 | int argIndex = tmpString.indexOf(','); 69 | if (argIndex) tmpString = tmpString.substring(0, argIndex); 70 | 71 | if (GetArgv(command, TmpStr1, 2)) IrType = TmpStr1; 72 | if (GetArgv(command, TmpStr1, 3)) IrCode = strtoul(TmpStr1, NULL, 16); //(long) TmpStr1 73 | if (GetArgv(command, TmpStr1, 4)) IrBits = str2int(TmpStr1); 74 | 75 | if (tmpString.equalsIgnoreCase("IRSEND") && Plugin_035_irSender != 0) 76 | { 77 | success = true; 78 | if (irReceiver != 0) irReceiver->disableIRIn(); // Stop the receiver 79 | 80 | if (IrType.equalsIgnoreCase("NEC")) Plugin_035_irSender->sendNEC(IrCode, IrBits); 81 | if (IrType.equalsIgnoreCase("JVC")) Plugin_035_irSender->sendJVC(IrCode, IrBits, 2); 82 | if (IrType.equalsIgnoreCase("RC5")) Plugin_035_irSender->sendRC5(IrCode, IrBits); 83 | if (IrType.equalsIgnoreCase("RC6")) Plugin_035_irSender->sendRC6(IrCode, IrBits); 84 | if (IrType.equalsIgnoreCase("SAMSUNG")) Plugin_035_irSender->sendSAMSUNG(IrCode, IrBits); 85 | if (IrType.equalsIgnoreCase("SONY")) Plugin_035_irSender->sendSony(IrCode, IrBits); 86 | if (IrType.equalsIgnoreCase("PANASONIC")) Plugin_035_irSender->sendPanasonic(IrBits, IrCode); 87 | 88 | addLog(LOG_LEVEL_INFO, "IR Code Sent"); 89 | if (printToWeb) 90 | { 91 | printWebString += F("IR Code Sent "); 92 | printWebString += IrType; 93 | printWebString += F("
"); 94 | } 95 | 96 | if (irReceiver != 0) irReceiver->enableIRIn(); // Start the receiver 97 | } 98 | break; 99 | } 100 | } 101 | return success; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /_C006.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 006: PiDome MQTT ######################################## 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_006 6 | #define CPLUGIN_ID_006 6 7 | #define CPLUGIN_NAME_006 "PiDome MQTT" 8 | 9 | boolean CPlugin_006(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_006; 18 | Protocol[protocolCount].usesMQTT = true; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = false; 21 | Protocol[protocolCount].usesPassword = false; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_006); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTsubscribe, PSTR("/Home/#")); 35 | strcpy_P(Settings.MQTTpublish, PSTR("/hooks/devices/%id%/SensorData/%valname%")); 36 | break; 37 | } 38 | 39 | case CPLUGIN_PROTOCOL_RECV: 40 | { 41 | // topic structure /Home/Floor/Location/device//gpio/16 42 | // Split topic into array 43 | String tmpTopic = event->String1.substring(1); 44 | String topicSplit[10]; 45 | int SlashIndex = tmpTopic.indexOf('/'); 46 | byte count = 0; 47 | while (SlashIndex > 0 && count < 10 - 1) 48 | { 49 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 50 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 51 | SlashIndex = tmpTopic.indexOf('/'); 52 | count++; 53 | } 54 | topicSplit[count] = tmpTopic; 55 | 56 | String name = topicSplit[4]; 57 | String cmd = topicSplit[5]; 58 | struct EventStruct TempEvent; 59 | TempEvent.Par1 = topicSplit[6].toInt(); 60 | TempEvent.Par2 = 0; 61 | TempEvent.Par3 = 0; 62 | if (event->String2 == "false" || event->String2 == "true") 63 | { 64 | if (event->String2 == "true") 65 | TempEvent.Par2 = 1; 66 | } 67 | else 68 | TempEvent.Par2 = event->String2.toFloat(); 69 | if (name == Settings.Name) 70 | { 71 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 72 | } 73 | break; 74 | } 75 | 76 | case CPLUGIN_PROTOCOL_SEND: 77 | { 78 | statusLED(true); 79 | 80 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 81 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 82 | 83 | String pubname = Settings.MQTTpublish; 84 | pubname.replace("%sysname%", Settings.Name); 85 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 86 | pubname.replace("%id%", String(event->idx)); 87 | 88 | String value = ""; 89 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 90 | byte valueCount = getValueCountFromSensorType(event->sensorType); 91 | for (byte x = 0; x < valueCount; x++) 92 | { 93 | String tmppubname = pubname; 94 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[x]); 95 | if (event->sensorType == SENSOR_TYPE_LONG) 96 | value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 97 | else 98 | value = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 99 | MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag); 100 | } 101 | break; 102 | } 103 | return success; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /_P033_Dummy.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 033: Dummy ################################################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_033 6 | #define PLUGIN_ID_033 33 7 | #define PLUGIN_NAME_033 "Dummy Device" 8 | #define PLUGIN_VALUENAME1_033 "Dummy" 9 | boolean Plugin_033(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | 16 | case PLUGIN_DEVICE_ADD: 17 | { 18 | Device[++deviceCount].Number = PLUGIN_ID_033; 19 | Device[deviceCount].Type = DEVICE_TYPE_DUMMY; 20 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 21 | Device[deviceCount].Ports = 0; 22 | Device[deviceCount].PullUpOption = false; 23 | Device[deviceCount].InverseLogicOption = false; 24 | Device[deviceCount].FormulaOption = false; 25 | Device[deviceCount].DecimalsOnly = true; 26 | Device[deviceCount].ValueCount = 4; 27 | Device[deviceCount].SendDataOption = true; 28 | Device[deviceCount].TimerOption = true; 29 | Device[deviceCount].GlobalSyncOption = true; 30 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_033); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_033)); 42 | break; 43 | } 44 | 45 | case PLUGIN_WEBFORM_LOAD: 46 | { 47 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 48 | String options[9]; 49 | options[0] = F("SENSOR_TYPE_SINGLE"); 50 | options[1] = F("SENSOR_TYPE_TEMP_HUM"); 51 | options[2] = F("SENSOR_TYPE_TEMP_BARO"); 52 | options[3] = F("SENSOR_TYPE_TEMP_HUM_BARO"); 53 | options[4] = F("SENSOR_TYPE_DUAL"); 54 | options[5] = F("SENSOR_TYPE_TRIPLE"); 55 | options[6] = F("SENSOR_TYPE_QUAD"); 56 | options[7] = F("SENSOR_TYPE_SWITCH"); 57 | options[8] = F("SENSOR_TYPE_DIMMER"); 58 | int optionValues[9]; 59 | optionValues[0] = SENSOR_TYPE_SINGLE; 60 | optionValues[1] = SENSOR_TYPE_TEMP_HUM; 61 | optionValues[2] = SENSOR_TYPE_TEMP_BARO; 62 | optionValues[3] = SENSOR_TYPE_TEMP_HUM_BARO; 63 | optionValues[4] = SENSOR_TYPE_DUAL; 64 | optionValues[5] = SENSOR_TYPE_TRIPLE; 65 | optionValues[6] = SENSOR_TYPE_QUAD; 66 | optionValues[7] = SENSOR_TYPE_SWITCH; 67 | optionValues[8] = SENSOR_TYPE_DIMMER; 68 | string += F("Simulate Data Type:"); 81 | 82 | success = true; 83 | break; 84 | } 85 | 86 | case PLUGIN_WEBFORM_SAVE: 87 | { 88 | String plugin1 = WebServer.arg("plugin_033_sensortype"); 89 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 90 | success = true; 91 | break; 92 | } 93 | 94 | case PLUGIN_READ: 95 | { 96 | event->sensorType =Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 97 | for (byte x=0; x<4;x++) 98 | { 99 | String log = F("Dummy: value "); 100 | log += x+1; 101 | log += F(": "); 102 | log += UserVar[event->BaseVarIndex+x]; 103 | addLog(LOG_LEVEL_INFO,log); 104 | } 105 | success = true; 106 | break; 107 | } 108 | } 109 | return success; 110 | } 111 | 112 | -------------------------------------------------------------------------------- /_C005.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 005: OpenHAB MQTT ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_005 6 | #define CPLUGIN_ID_005 5 7 | #define CPLUGIN_NAME_005 "OpenHAB MQTT" 8 | 9 | boolean CPlugin_005(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_005; 18 | Protocol[protocolCount].usesMQTT = true; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_005); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTsubscribe, PSTR("/%sysname%/#")); 35 | strcpy_P(Settings.MQTTpublish, PSTR("/%sysname%/%tskname%/%valname%")); 36 | break; 37 | } 38 | 39 | case CPLUGIN_PROTOCOL_RECV: 40 | { 41 | // Split topic into array 42 | String tmpTopic = event->String1.substring(1); 43 | String topicSplit[10]; 44 | int SlashIndex = tmpTopic.indexOf('/'); 45 | byte count = 0; 46 | while (SlashIndex > 0 && count < 10 - 1) 47 | { 48 | topicSplit[count] = tmpTopic.substring(0, SlashIndex); 49 | tmpTopic = tmpTopic.substring(SlashIndex + 1); 50 | SlashIndex = tmpTopic.indexOf('/'); 51 | count++; 52 | } 53 | topicSplit[count] = tmpTopic; 54 | 55 | String cmd = ""; 56 | struct EventStruct TempEvent; 57 | 58 | if (topicSplit[count] == "cmd") 59 | { 60 | cmd = event->String2; 61 | parseCommandString(&TempEvent, cmd); 62 | TempEvent.Source = VALUE_SOURCE_MQTT; 63 | } 64 | else 65 | { 66 | cmd = topicSplit[count - 1]; 67 | TempEvent.Par1 = topicSplit[count].toInt(); 68 | TempEvent.Par2 = event->String2.toFloat(); 69 | TempEvent.Par3 = 0; 70 | } 71 | // in case of event, store to buffer and return... 72 | String command = parseString(cmd, 1); 73 | if (command == F("event")) 74 | eventBuffer = cmd.substring(6); 75 | else 76 | PluginCall(PLUGIN_WRITE, &TempEvent, cmd); 77 | break; 78 | } 79 | 80 | case CPLUGIN_PROTOCOL_SEND: 81 | { 82 | statusLED(true); 83 | 84 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 85 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 86 | 87 | String pubname = Settings.MQTTpublish; 88 | pubname.replace("%sysname%", Settings.Name); 89 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 90 | pubname.replace("%id%", String(event->idx)); 91 | 92 | String value = ""; 93 | byte DeviceIndex = getDeviceIndex(Settings.TaskDeviceNumber[event->TaskIndex]); 94 | byte valueCount = getValueCountFromSensorType(event->sensorType); 95 | for (byte x = 0; x < valueCount; x++) 96 | { 97 | String tmppubname = pubname; 98 | tmppubname.replace("%valname%", ExtraTaskSettings.TaskDeviceValueNames[x]); 99 | if (event->sensorType == SENSOR_TYPE_LONG) 100 | value = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 101 | else 102 | value = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 103 | MQTTclient.publish(tmppubname.c_str(), value.c_str(), Settings.MQTTRetainFlag); 104 | } 105 | break; 106 | } 107 | return success; 108 | } 109 | } 110 | 111 | -------------------------------------------------------------------------------- /_C004.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 004: ThingSpeak ######################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_004 6 | #define CPLUGIN_ID_004 4 7 | #define CPLUGIN_NAME_004 "ThingSpeak" 8 | 9 | boolean CPlugin_004(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_004; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 80; 22 | break; 23 | } 24 | 25 | case CPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(CPLUGIN_NAME_004); 28 | break; 29 | } 30 | 31 | case CPLUGIN_PROTOCOL_SEND: 32 | { 33 | char log[80]; 34 | boolean success = false; 35 | char host[20]; 36 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 37 | 38 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 39 | addLog(LOG_LEVEL_DEBUG, log); 40 | 41 | // Use WiFiClient class to create TCP connections 42 | WiFiClient client; 43 | if (!client.connect(host, Settings.ControllerPort)) 44 | { 45 | connectionFailures++; 46 | strcpy_P(log, PSTR("HTTP : connection failed")); 47 | addLog(LOG_LEVEL_ERROR, log); 48 | return false; 49 | } 50 | statusLED(true); 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | String postDataStr = F("api_key="); 55 | postDataStr += SecuritySettings.ControllerPassword; // used for API key 56 | 57 | byte valueCount = getValueCountFromSensorType(event->sensorType); 58 | for (byte x = 0; x < valueCount; x++) 59 | { 60 | postDataStr += F("&field"); 61 | postDataStr += event->idx + x; 62 | postDataStr += "="; 63 | postDataStr += toString(UserVar[event->BaseVarIndex + x],ExtraTaskSettings.TaskDeviceValueDecimals[x]); 64 | } 65 | String hostName = F("api.thingspeak.com"); // PM_CZ: HTTP requests must contain host headers. 66 | if (Settings.UseDNS) 67 | hostName = Settings.ControllerHostName; 68 | 69 | String postStr = F("POST /update HTTP/1.1\r\n"); 70 | postStr += F("Host: "); 71 | postStr += hostName; 72 | postStr += F("\r\n"); 73 | postStr += F("Connection: close\r\n"); 74 | 75 | postStr += F("Content-Type: application/x-www-form-urlencoded\r\n"); 76 | postStr += F("Content-Length: "); 77 | postStr += postDataStr.length(); 78 | postStr += F("\r\n\r\n"); 79 | postStr += postDataStr; 80 | 81 | // This will send the request to the server 82 | client.print(postStr); 83 | 84 | unsigned long timer = millis() + 200; 85 | while (!client.available() && millis() < timer) 86 | delay(1); 87 | 88 | // Read all the lines of the reply from server and print them to Serial 89 | while (client.available()) { 90 | String line = client.readStringUntil('\n'); 91 | line.toCharArray(log, 80); 92 | addLog(LOG_LEVEL_DEBUG_MORE, log); 93 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 94 | { 95 | strcpy_P(log, PSTR("HTTP : Succes!")); 96 | addLog(LOG_LEVEL_DEBUG, log); 97 | success = true; 98 | } 99 | delay(1); 100 | } 101 | strcpy_P(log, PSTR("HTTP : closing connection")); 102 | addLog(LOG_LEVEL_DEBUG, log); 103 | 104 | client.flush(); 105 | client.stop(); 106 | break; 107 | } 108 | 109 | } 110 | return success; 111 | } 112 | 113 | -------------------------------------------------------------------------------- /_P034_DHT12.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 034: Temperature and Humidity sensor DHT 12 (I2C) ##################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_034 6 | #define PLUGIN_ID_034 34 7 | #define PLUGIN_NAME_034 "Temperature & Humidity - DHT12 (I2C)" 8 | #define PLUGIN_VALUENAME1_034 "Temperature" 9 | #define PLUGIN_VALUENAME2_034 "Humidity" 10 | 11 | boolean Plugin_034_init = false; 12 | 13 | #define DHT12_I2C_ADDRESS 0x5C // I2C address for the sensor 14 | 15 | boolean Plugin_034(byte function, struct EventStruct *event, String& string) 16 | { 17 | boolean success = false; 18 | 19 | switch (function) 20 | { 21 | case PLUGIN_DEVICE_ADD: 22 | { 23 | Device[++deviceCount].Number = PLUGIN_ID_034; 24 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 25 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 26 | Device[deviceCount].Ports = 0; 27 | Device[deviceCount].PullUpOption = false; 28 | Device[deviceCount].InverseLogicOption = false; 29 | Device[deviceCount].FormulaOption = true; 30 | Device[deviceCount].ValueCount = 2; 31 | Device[deviceCount].SendDataOption = true; 32 | Device[deviceCount].TimerOption = true; 33 | Device[deviceCount].GlobalSyncOption = true; 34 | break; 35 | } 36 | 37 | case PLUGIN_GET_DEVICENAME: 38 | { 39 | string = F(PLUGIN_NAME_034); 40 | break; 41 | } 42 | 43 | case PLUGIN_GET_DEVICEVALUENAMES: 44 | { 45 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_034)); 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_034)); 47 | break; 48 | } 49 | 50 | case PLUGIN_READ: 51 | { 52 | byte dht_dat[5]; 53 | byte dht_in; 54 | byte i; 55 | byte Retry = 0; 56 | boolean error = false; 57 | 58 | Wire.beginTransmission(DHT12_I2C_ADDRESS); // start transmission to device 59 | Wire.write(0); // sends register address to read from 60 | Wire.endTransmission(); // end transmission 61 | 62 | Wire.beginTransmission(DHT12_I2C_ADDRESS); // start transmission to device 63 | if (Wire.requestFrom(DHT12_I2C_ADDRESS, 5) == 5) { // send data n-bytes read 64 | for (i = 0; i < 5; i++) 65 | { 66 | dht_dat[i] = Wire.read(); // receive DATA 67 | } 68 | } else { 69 | error = true; 70 | } 71 | if (!error) 72 | { 73 | // Checksum calculation is a Rollover Checksum by design! 74 | byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum 75 | 76 | if (dht_dat[4] == dht_check_sum) 77 | { 78 | float temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature 79 | if (dht_dat[3] & 0x80) { temperature = -temperature; } 80 | float humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity 81 | 82 | UserVar[event->BaseVarIndex] = temperature; 83 | UserVar[event->BaseVarIndex + 1] = humidity; 84 | String log = F("DHT12: Temperature: "); 85 | log += UserVar[event->BaseVarIndex]; 86 | addLog(LOG_LEVEL_INFO, log); 87 | log = F("DHT12: Humidity: "); 88 | log += UserVar[event->BaseVarIndex + 1]; 89 | addLog(LOG_LEVEL_INFO, log); 90 | /* 91 | log = F("DHT12: Data: "); 92 | for (int i=0; i < 5; i++) 93 | { 94 | log += dht_dat[i]; 95 | log += ", "; 96 | } 97 | addLog(LOG_LEVEL_INFO, log); 98 | */ 99 | success = true; 100 | } // checksum 101 | } // error 102 | if(!success) 103 | { 104 | String log = F("DHT12: No reading!"); 105 | addLog(LOG_LEVEL_INFO, log); 106 | UserVar[event->BaseVarIndex] = NAN; 107 | UserVar[event->BaseVarIndex + 1] = NAN; 108 | } 109 | break; 110 | } 111 | } 112 | return success; 113 | } 114 | -------------------------------------------------------------------------------- /_P022_PCA9685.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 022: PCA9685 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_022 6 | #define PLUGIN_ID_022 22 7 | #define PLUGIN_NAME_022 "PWM - PCA9685" 8 | #define PLUGIN_VALUENAME1_022 "PWM" 9 | 10 | #define PCA9685_MODE1 0x00 // location for Mode1 register address 11 | #define PCA9685_MODE2 0x01 // location for Mode2 reigster address 12 | #define PCA9685_LED0 0x06 // location for start of LED0 registers 13 | #define PCA9685_ADDRESS 0x40 // I2C address 14 | 15 | boolean Plugin_022_init = false; 16 | 17 | boolean Plugin_022(byte function, struct EventStruct *event, String& string) 18 | { 19 | boolean success = false; 20 | static byte switchstate[TASKS_MAX]; 21 | 22 | switch (function) 23 | { 24 | case PLUGIN_DEVICE_ADD: 25 | { 26 | Device[++deviceCount].Number = PLUGIN_ID_022; 27 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 28 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 29 | Device[deviceCount].Ports = 0; 30 | Device[deviceCount].PullUpOption = false; 31 | Device[deviceCount].InverseLogicOption = false; 32 | Device[deviceCount].FormulaOption = false; 33 | Device[deviceCount].ValueCount = 0; 34 | Device[deviceCount].Custom = true; 35 | Device[deviceCount].TimerOption = false; 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICENAME: 40 | { 41 | string = F(PLUGIN_NAME_022); 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICEVALUENAMES: 46 | { 47 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_022)); 48 | break; 49 | } 50 | 51 | case PLUGIN_WRITE: 52 | { 53 | String log = ""; 54 | if (!Plugin_022_init) 55 | { 56 | // default mode is open drain ouput, drive leds connected to VCC 57 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)0x01); // reset the device 58 | delay(1); 59 | Plugin_022_writeRegister(PCA9685_MODE1, (byte)B10100000); // set up for auto increment 60 | Plugin_022_writeRegister(PCA9685_MODE2, (byte)0x10); // set to output 61 | Plugin_022_init = true; 62 | } 63 | 64 | String command = parseString(string, 1); 65 | 66 | if (command == F("pcapwm")) 67 | { 68 | success = true; 69 | Plugin_022_Write(event->Par1, event->Par2); 70 | setPinState(PLUGIN_ID_022, event->Par1, PIN_MODE_PWM, event->Par2); 71 | log = String(F("PCA : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); 72 | addLog(LOG_LEVEL_INFO, log); 73 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par1, log, 0)); 74 | } 75 | 76 | if (command == F("status")) 77 | { 78 | if (parseString(string, 2) == F("pca")) 79 | { 80 | success = true; 81 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_022, event->Par2, dummyString, 0)); 82 | } 83 | } 84 | break; 85 | } 86 | } 87 | return success; 88 | } 89 | 90 | 91 | //******************************************************************************** 92 | // PCA9685 config 93 | //******************************************************************************** 94 | void Plugin_022_writeRegister(int regAddress, byte data) { 95 | Wire.beginTransmission(PCA9685_ADDRESS); 96 | Wire.write(regAddress); 97 | Wire.write(data); 98 | Wire.endTransmission(); 99 | } 100 | 101 | 102 | //******************************************************************************** 103 | // PCA9685 write 104 | //******************************************************************************** 105 | boolean Plugin_022_Write(byte Par1, int Par2) 106 | { 107 | boolean success = false; 108 | uint16_t LED_ON = 0; 109 | uint16_t LED_OFF = Par2; 110 | Wire.beginTransmission(PCA9685_ADDRESS); 111 | Wire.write(0x06 + 4 * Par1); 112 | Wire.write(lowByte(LED_ON)); 113 | Wire.write(highByte(LED_ON)); 114 | Wire.write(lowByte(LED_OFF)); 115 | Wire.write(highByte(LED_OFF)); 116 | Wire.endTransmission(); 117 | } 118 | 119 | -------------------------------------------------------------------------------- /_P010_BH1750.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin-010: LuxRead ############################################ 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_010 6 | #define PLUGIN_ID_010 10 7 | #define PLUGIN_NAME_010 "Luminosity - BH1750" 8 | #define PLUGIN_VALUENAME1_010 "Lux" 9 | 10 | #define BH1750_ADDRESS_1 0x23 11 | #define BH1750_ADDRESS_2 0x5c 12 | boolean Plugin_010_init_1 = false; 13 | boolean Plugin_010_init_2 = false; 14 | 15 | boolean Plugin_010(byte function, struct EventStruct *event, String& string) 16 | { 17 | boolean success=false; 18 | 19 | switch(function) 20 | { 21 | 22 | case PLUGIN_DEVICE_ADD: 23 | { 24 | Device[++deviceCount].Number = PLUGIN_ID_010; 25 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 26 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 27 | Device[deviceCount].Ports = 0; 28 | Device[deviceCount].PullUpOption = false; 29 | Device[deviceCount].InverseLogicOption = false; 30 | Device[deviceCount].FormulaOption = true; 31 | Device[deviceCount].ValueCount = 1; 32 | Device[deviceCount].SendDataOption = true; 33 | Device[deviceCount].TimerOption = true; 34 | Device[deviceCount].GlobalSyncOption = true; 35 | break; 36 | } 37 | 38 | case PLUGIN_GET_DEVICENAME: 39 | { 40 | string = F(PLUGIN_NAME_010); 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICEVALUENAMES: 45 | { 46 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_010)); 47 | break; 48 | } 49 | 50 | case PLUGIN_WEBFORM_LOAD: 51 | { 52 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 53 | String options[2]; 54 | options[0] = F("0x23 - default settings (ADDR Low)"); 55 | options[1] = F("0x5c - alternate settings (ADDR High)"); 56 | int optionValues[2]; 57 | optionValues[0] = 0; 58 | optionValues[1] = 1; 59 | string += F("I2C Address:"); 72 | 73 | success = true; 74 | break; 75 | } 76 | 77 | case PLUGIN_WEBFORM_SAVE: 78 | { 79 | String plugin1 = WebServer.arg("plugin_010"); 80 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_READ: 86 | { 87 | uint8_t address = -1; 88 | boolean *Plugin_010_init; 89 | 90 | if(Settings.TaskDevicePluginConfig[event->TaskIndex][0]==0) 91 | { 92 | address = BH1750_ADDRESS_1; 93 | Plugin_010_init = &Plugin_010_init_1; 94 | } 95 | else 96 | { 97 | address = BH1750_ADDRESS_2; 98 | Plugin_010_init = &Plugin_010_init_2; 99 | } 100 | 101 | if (!*Plugin_010_init) 102 | { 103 | *Plugin_010_init = Plugin_010_setResolution(address); 104 | } 105 | 106 | if (Wire.requestFrom(address, (uint8_t)2) == 2) 107 | { 108 | byte b1 = Wire.read(); 109 | byte b2 = Wire.read(); 110 | float val = 0xffff; //pm-cz: Maximum obtainable value 111 | if (b1 != 0xff || b2 != 0xff) { //pm-cz: Add maximum range check 112 | val=((b1<<8)|b2)/1.2; 113 | } 114 | UserVar[event->BaseVarIndex] = val; 115 | String log = F("LUX 0x"); 116 | log += String(address,HEX); 117 | log += F(" : Light intensity: "); 118 | log += UserVar[event->BaseVarIndex]; 119 | addLog(LOG_LEVEL_INFO,log); 120 | success=true; 121 | } 122 | break; 123 | } 124 | } 125 | return success; 126 | } 127 | 128 | boolean Plugin_010_setResolution(uint8_t address){ 129 | Wire.beginTransmission(address); 130 | Wire.write(0x10); // 1 lx resolution 131 | Wire.endTransmission(); 132 | return true; 133 | } 134 | -------------------------------------------------------------------------------- /_P008_RFID.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################################# Plugin 008: Wiegand RFID Tag Reader ################################# 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_008 6 | #define PLUGIN_ID_008 8 7 | #define PLUGIN_NAME_008 "RFID Reader - Wiegand" 8 | #define PLUGIN_VALUENAME1_008 "Tag" 9 | 10 | #define PLUGIN_008_WGSIZE 26 11 | 12 | void Plugin_008_interrupt1() ICACHE_RAM_ATTR; 13 | void Plugin_008_interrupt2() ICACHE_RAM_ATTR; 14 | 15 | volatile byte Plugin_008_bitCount = 0; // Count the number of bits received. 16 | volatile unsigned long Plugin_008_keyBuffer = 0; // A 32-bit-long keyBuffer into which the number is stored. 17 | byte Plugin_008_bitCountPrev = 0; // to detect noise 18 | byte Plugin_008_Unit = 0; 19 | 20 | boolean Plugin_008_init = false; 21 | 22 | boolean Plugin_008(byte function, struct EventStruct *event, String& string) 23 | { 24 | boolean success = false; 25 | 26 | switch (function) 27 | { 28 | case PLUGIN_DEVICE_ADD: 29 | { 30 | Device[++deviceCount].Number = PLUGIN_ID_008; 31 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 32 | Device[deviceCount].VType = SENSOR_TYPE_LONG; 33 | Device[deviceCount].Ports = 0; 34 | Device[deviceCount].PullUpOption = false; 35 | Device[deviceCount].InverseLogicOption = false; 36 | Device[deviceCount].FormulaOption = false; 37 | Device[deviceCount].ValueCount = 1; 38 | Device[deviceCount].SendDataOption = true; 39 | Device[deviceCount].TimerOption = false; 40 | Device[deviceCount].GlobalSyncOption = true; 41 | break; 42 | } 43 | 44 | case PLUGIN_GET_DEVICENAME: 45 | { 46 | string = F(PLUGIN_NAME_008); 47 | break; 48 | } 49 | 50 | case PLUGIN_GET_DEVICEVALUENAMES: 51 | { 52 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_008)); 53 | break; 54 | } 55 | 56 | case PLUGIN_INIT: 57 | { 58 | Plugin_008_init = true; 59 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 60 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 61 | attachInterrupt(Settings.TaskDevicePin1[event->TaskIndex], Plugin_008_interrupt1, FALLING); 62 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_008_interrupt2, FALLING); 63 | success = true; 64 | break; 65 | } 66 | 67 | case PLUGIN_ONCE_A_SECOND: 68 | { 69 | if (Plugin_008_init) 70 | { 71 | if ((Plugin_008_bitCount != PLUGIN_008_WGSIZE) && (Plugin_008_bitCount == Plugin_008_bitCountPrev)) 72 | { 73 | // must be noise 74 | Plugin_008_bitCount = 0; 75 | Plugin_008_keyBuffer = 0; 76 | } 77 | 78 | if (Plugin_008_bitCount == PLUGIN_008_WGSIZE) 79 | { 80 | Plugin_008_bitCount = 0; // Read in the current key and reset everything so that the interrupts can 81 | 82 | Plugin_008_keyBuffer = Plugin_008_keyBuffer >> 1; // Strip leading and trailing parity bits from the keyBuffer 83 | Plugin_008_keyBuffer &= 0xFFFFFF; 84 | UserVar[event->BaseVarIndex] = (Plugin_008_keyBuffer & 0xFFFF); 85 | UserVar[event->BaseVarIndex + 1] = ((Plugin_008_keyBuffer >> 16) & 0xFFFF); 86 | String log = F("RFID : Tag: "); 87 | log += Plugin_008_keyBuffer; 88 | addLog(LOG_LEVEL_INFO, log); 89 | sendData(event); 90 | } 91 | 92 | Plugin_008_bitCountPrev = Plugin_008_bitCount; // store this value for next check, detect noise 93 | } 94 | break; 95 | } 96 | } 97 | return success; 98 | } 99 | 100 | /*********************************************************************/ 101 | void Plugin_008_interrupt1() 102 | /*********************************************************************/ 103 | { 104 | // We've received a 1 bit. (bit 0 = high, bit 1 = low) 105 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 106 | Plugin_008_keyBuffer += 1; // Add the 1 (not necessary for the zeroes) 107 | Plugin_008_bitCount++; // Increment the bit count 108 | } 109 | 110 | /*********************************************************************/ 111 | void Plugin_008_interrupt2() 112 | /*********************************************************************/ 113 | { 114 | // We've received a 0 bit. (bit 0 = low, bit 1 = high) 115 | Plugin_008_keyBuffer = Plugin_008_keyBuffer << 1; // Left shift the number (effectively multiplying by 2) 116 | Plugin_008_bitCount++; // Increment the bit count 117 | } 118 | 119 | -------------------------------------------------------------------------------- /_P024_MLX90614.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 024: MLX90614 IR temperature I2C 0x5A) ############################################### 3 | //####################################################################################################### 4 | 5 | // MyMessage *msgTemp024; // Mysensors 6 | 7 | #define PLUGIN_024 8 | #define PLUGIN_ID_024 24 9 | #define PLUGIN_NAME_024 "Temperature IR + ambient - MLX90614" 10 | #define PLUGIN_VALUENAME1_024 "Temperature" 11 | 12 | boolean Plugin_024_init = false; 13 | 14 | uint16_t readRegister024(uint8_t i2cAddress, uint8_t reg) { 15 | uint16_t ret; 16 | Wire.beginTransmission(i2cAddress); 17 | Wire.write(reg); 18 | Wire.endTransmission(false); 19 | Wire.requestFrom(i2cAddress, (uint8_t)3); 20 | ret = Wire.read(); // receive DATA 21 | ret |= Wire.read() << 8; // receive DATA 22 | uint8_t pec = Wire.read(); 23 | return ret; 24 | } 25 | 26 | float readTemp024(uint8_t i2c_addr, uint8_t i2c_reg) 27 | { 28 | float temp; 29 | temp = readRegister024(i2c_addr, i2c_reg); 30 | temp *= .02; 31 | temp -= 273.15; 32 | return temp; 33 | } 34 | 35 | boolean Plugin_024(byte function, struct EventStruct *event, String& string) 36 | { 37 | boolean success = false; 38 | static byte portValue = 0; 39 | switch (function) 40 | { 41 | case PLUGIN_DEVICE_ADD: 42 | { 43 | Device[++deviceCount].Number = PLUGIN_ID_024; 44 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 45 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 46 | Device[deviceCount].Ports = 16; 47 | Device[deviceCount].PullUpOption = false; 48 | Device[deviceCount].InverseLogicOption = false; 49 | Device[deviceCount].FormulaOption = true; 50 | Device[deviceCount].SendDataOption = true; 51 | Device[deviceCount].ValueCount = 1; 52 | Device[deviceCount].TimerOption = true; 53 | Device[deviceCount].GlobalSyncOption = true; 54 | break; 55 | } 56 | 57 | case PLUGIN_GET_DEVICENAME: 58 | { 59 | string = F(PLUGIN_NAME_024); 60 | break; 61 | } 62 | 63 | case PLUGIN_GET_DEVICEVALUENAMES: 64 | { 65 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_024)); 66 | break; 67 | } 68 | 69 | case PLUGIN_WEBFORM_LOAD: 70 | { 71 | #define MLX90614_OPTION 2 72 | 73 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 74 | String options[MLX90614_OPTION]; 75 | uint optionValues[MLX90614_OPTION]; 76 | optionValues[0] = (0x07); 77 | options[0] = F("IR object temperature"); 78 | optionValues[1] = (0x06); 79 | options[1] = F("Ambient temperature"); 80 | string += F("Option:"); 93 | 94 | success = true; 95 | break; 96 | } 97 | 98 | case PLUGIN_WEBFORM_SAVE: 99 | { 100 | String plugin1 = WebServer.arg("plugin_024_option"); 101 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 102 | Plugin_024_init = false; // Force device setup next time 103 | success = true; 104 | break; 105 | } 106 | 107 | case PLUGIN_INIT: 108 | { 109 | Plugin_024_init = true; 110 | // if (!msgTemp024) // Mysensors 111 | // msgTemp024 = new MyMessage(event->BaseVarIndex, V_TEMP); //Mysensors 112 | // present(event->BaseVarIndex, S_TEMP); //Mysensors 113 | // Serial.print("Present MLX90614: "); //Mysensors 114 | // Serial.println(event->BaseVarIndex); //Mysensors 115 | success = true; 116 | break; 117 | } 118 | 119 | case PLUGIN_READ: 120 | { 121 | // noInterrupts(); 122 | int value; 123 | value = 0; 124 | byte unit = Settings.TaskDevicePort[event->TaskIndex]; 125 | uint8_t address = 0x5A + unit; 126 | UserVar[event->BaseVarIndex] = (float) readTemp024(address, Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 127 | String log = F("MLX90614 : Temperature: "); 128 | log += UserVar[event->BaseVarIndex]; 129 | // send(msgObjTemp024->set(UserVar[event->BaseVarIndex], 1)); // Mysensors 130 | addLog(LOG_LEVEL_INFO,log); 131 | success = true; 132 | // interrupts(); 133 | break; 134 | } 135 | } 136 | return success; 137 | } 138 | -------------------------------------------------------------------------------- /_P021_Level.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 021: Level Control ######################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_021 6 | #define PLUGIN_ID_021 21 7 | #define PLUGIN_NAME_021 "Level Control" 8 | #define PLUGIN_VALUENAME1_021 "Output" 9 | 10 | boolean Plugin_021(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte switchstate[TASKS_MAX]; 14 | 15 | switch (function) 16 | { 17 | 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_021; 21 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 22 | Device[deviceCount].VType = SENSOR_TYPE_SWITCH; 23 | Device[deviceCount].Ports = 0; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = false; 30 | break; 31 | } 32 | 33 | case PLUGIN_GET_DEVICENAME: 34 | { 35 | string = F(PLUGIN_NAME_021); 36 | break; 37 | } 38 | 39 | case PLUGIN_GET_DEVICEVALUENAMES: 40 | { 41 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_021)); 42 | break; 43 | } 44 | 45 | case PLUGIN_WEBFORM_LOAD: 46 | { 47 | char tmpString[128]; 48 | 49 | string += F("Check Task:"); 50 | addTaskSelect(string, "plugin_021_task", Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 51 | 52 | LoadTaskSettings(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); // we need to load the values from another task for selection! 53 | string += F("Check Value:"); 54 | addTaskValueSelect(string, "plugin_021_value", Settings.TaskDevicePluginConfig[event->TaskIndex][1], Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 55 | 56 | string += F("Set Value:"); 59 | string += F("Hysteresis:"); 62 | 63 | LoadTaskSettings(event->TaskIndex); // we need to restore our original taskvalues! 64 | success = true; 65 | break; 66 | } 67 | 68 | case PLUGIN_WEBFORM_SAVE: 69 | { 70 | String plugin1 = WebServer.arg("plugin_021_task"); 71 | String plugin2 = WebServer.arg("plugin_021_value"); 72 | String plugin3 = WebServer.arg("plugin_021_setvalue"); 73 | String plugin4 = WebServer.arg("plugin_021_hyst"); 74 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 75 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 76 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] = plugin3.toFloat(); 77 | Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] = plugin4.toFloat(); 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_INIT: 83 | { 84 | Serial.print(F("INIT : Output ")); 85 | Serial.println(Settings.TaskDevicePin1[event->TaskIndex]); 86 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 87 | success = true; 88 | break; 89 | } 90 | 91 | case PLUGIN_TEN_PER_SECOND: 92 | { 93 | // we're checking a var from another task, so calculate that basevar 94 | byte TaskIndex = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 95 | byte BaseVarIndex = TaskIndex * VARS_PER_TASK + Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 96 | float value = UserVar[BaseVarIndex]; 97 | byte state = switchstate[event->TaskIndex]; 98 | // compare with threshold value 99 | float valueLowThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] - (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 100 | float valueHighThreshold = Settings.TaskDevicePluginConfigFloat[event->TaskIndex][0] + (Settings.TaskDevicePluginConfigFloat[event->TaskIndex][1] / 2); 101 | if (value <= valueLowThreshold) 102 | state = 1; 103 | if (value >= valueHighThreshold) 104 | state = 0; 105 | if (state != switchstate[event->TaskIndex]) 106 | { 107 | Serial.print(F("Out : State ")); 108 | Serial.println(state); 109 | switchstate[event->TaskIndex] = state; 110 | digitalWrite(Settings.TaskDevicePin1[event->TaskIndex],state); 111 | UserVar[event->BaseVarIndex] = state; 112 | sendData(event); 113 | } 114 | 115 | success = true; 116 | break; 117 | } 118 | 119 | } 120 | return success; 121 | } 122 | 123 | -------------------------------------------------------------------------------- /_C008.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 008: Generic HTTP ####################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_008 6 | #define CPLUGIN_ID_008 8 7 | #define CPLUGIN_NAME_008 "Generic HTTP" 8 | 9 | boolean CPlugin_008(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_008; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 80; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_008); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTpublish, PSTR("demo.php?name=%sysname%&task=%tskname%&valuename=%valname%&value=%value%")); 35 | break; 36 | } 37 | 38 | case CPLUGIN_PROTOCOL_SEND: 39 | { 40 | byte valueCount = getValueCountFromSensorType(event->sensorType); 41 | for (byte x = 0; x < valueCount; x++) 42 | { 43 | if (event->sensorType == SENSOR_TYPE_LONG) 44 | HTTPSend(event, 0, 0, (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16)); 45 | else 46 | HTTPSend(event, x, UserVar[event->BaseVarIndex + x], 0); 47 | if (valueCount > 1) 48 | { 49 | unsigned long timer = millis() + Settings.MessageDelay; 50 | while (millis() < timer) 51 | backgroundtasks(); 52 | } 53 | } 54 | break; 55 | } 56 | 57 | } 58 | return success; 59 | } 60 | 61 | 62 | //******************************************************************************** 63 | // Generic HTTP get request 64 | //******************************************************************************** 65 | boolean HTTPSend(struct EventStruct *event, byte varIndex, float value, unsigned long longValue) 66 | { 67 | String authHeader = ""; 68 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 69 | { 70 | base64 encoder; 71 | String auth = SecuritySettings.ControllerUser; 72 | auth += ":"; 73 | auth += SecuritySettings.ControllerPassword; 74 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 75 | } 76 | 77 | char log[80]; 78 | boolean success = false; 79 | char host[20]; 80 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 81 | 82 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host, Settings.ControllerPort); 83 | addLog(LOG_LEVEL_DEBUG, log); 84 | 85 | // Use WiFiClient class to create TCP connections 86 | WiFiClient client; 87 | if (!client.connect(host, Settings.ControllerPort)) 88 | { 89 | connectionFailures++; 90 | strcpy_P(log, PSTR("HTTP : connection failed")); 91 | addLog(LOG_LEVEL_ERROR, log); 92 | return false; 93 | } 94 | statusLED(true); 95 | if (connectionFailures) 96 | connectionFailures--; 97 | 98 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 99 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 100 | 101 | String url = "/"; 102 | url += Settings.MQTTpublish; 103 | url.replace("%sysname%", URLEncode(Settings.Name)); 104 | url.replace("%tskname%", URLEncode(ExtraTaskSettings.TaskDeviceName)); 105 | url.replace("%id%", String(event->idx)); 106 | url.replace("%valname%", URLEncode(ExtraTaskSettings.TaskDeviceValueNames[varIndex])); 107 | if (longValue) 108 | url.replace("%value%", String(longValue)); 109 | else 110 | url.replace("%value%", toString(value, ExtraTaskSettings.TaskDeviceValueDecimals[varIndex])); 111 | 112 | url.toCharArray(log, 80); 113 | addLog(LOG_LEVEL_DEBUG_MORE, log); 114 | 115 | String hostName = host; 116 | if (Settings.UseDNS) 117 | hostName = Settings.ControllerHostName; 118 | 119 | // This will send the request to the server 120 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 121 | "Host: " + hostName + "\r\n" + authHeader + 122 | "Connection: close\r\n\r\n"); 123 | 124 | unsigned long timer = millis() + 200; 125 | while (!client.available() && millis() < timer) 126 | delay(1); 127 | 128 | // Read all the lines of the reply from server and print them to Serial 129 | while (client.available()) { 130 | String line = client.readStringUntil('\n'); 131 | line.toCharArray(log, 80); 132 | addLog(LOG_LEVEL_DEBUG_MORE, log); 133 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 134 | { 135 | strcpy_P(log, PSTR("HTTP : Succes!")); 136 | addLog(LOG_LEVEL_DEBUG, log); 137 | success = true; 138 | } 139 | delay(1); 140 | } 141 | strcpy_P(log, PSTR("HTTP : closing connection")); 142 | addLog(LOG_LEVEL_DEBUG, log); 143 | 144 | client.flush(); 145 | client.stop(); 146 | } 147 | -------------------------------------------------------------------------------- /_C007.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 007: Emoncms ############################################ 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_007 6 | #define CPLUGIN_ID_007 7 7 | #define CPLUGIN_NAME_007 "Emoncms" 8 | 9 | boolean CPlugin_007(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_007; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = false; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 80; 22 | break; 23 | } 24 | 25 | case CPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(CPLUGIN_NAME_007); 28 | break; 29 | } 30 | 31 | case CPLUGIN_PROTOCOL_SEND: 32 | { 33 | char log[80]; 34 | boolean success = false; 35 | char host[20]; 36 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 37 | 38 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 39 | addLog(LOG_LEVEL_DEBUG, log); 40 | 41 | // Use WiFiClient class to create TCP connections 42 | WiFiClient client; 43 | if (!client.connect(host, Settings.ControllerPort)) 44 | { 45 | connectionFailures++; 46 | strcpy_P(log, PSTR("HTTP : connection failed")); 47 | addLog(LOG_LEVEL_ERROR, log); 48 | return false; 49 | } 50 | statusLED(true); 51 | if (connectionFailures) 52 | connectionFailures--; 53 | 54 | String postDataStr = F("GET /emoncms/input/post.json?node="); 55 | 56 | postDataStr += Settings.Unit; 57 | postDataStr += F("&json="); 58 | 59 | switch (event->sensorType) 60 | { 61 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 62 | postDataStr += F("{field"); 63 | postDataStr += event->idx; 64 | postDataStr += ":"; 65 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 66 | postDataStr += "}"; 67 | break; 68 | case SENSOR_TYPE_TEMP_HUM: // dual value 69 | case SENSOR_TYPE_TEMP_BARO: 70 | case SENSOR_TYPE_DUAL: 71 | postDataStr += F("{field"); 72 | postDataStr += event->idx; 73 | postDataStr += ":"; 74 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 75 | postDataStr += F(",field"); 76 | postDataStr += event->idx + 1; 77 | postDataStr += ":"; 78 | postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 79 | postDataStr += "}"; 80 | break; 81 | case SENSOR_TYPE_TEMP_HUM_BARO: 82 | case SENSOR_TYPE_TRIPLE: 83 | postDataStr += F("{field"); 84 | postDataStr += event->idx; 85 | postDataStr += ":"; 86 | postDataStr += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 87 | postDataStr += F(",field"); 88 | postDataStr += event->idx + 1; 89 | postDataStr += ":"; 90 | postDataStr += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 91 | postDataStr += F(",field"); 92 | postDataStr += event->idx + 2; 93 | postDataStr += ":"; 94 | postDataStr += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 95 | postDataStr += "}"; 96 | break; 97 | case SENSOR_TYPE_SWITCH: 98 | break; 99 | } 100 | postDataStr += F("&apikey="); 101 | postDataStr += SecuritySettings.ControllerPassword; // "0UDNN17RW6XAS2E5" // api key 102 | 103 | String hostName = host; 104 | if (Settings.UseDNS) 105 | hostName = Settings.ControllerHostName; 106 | 107 | String postStr = F(" 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 | postStr += F("\r\n"); 113 | 114 | postDataStr += postStr; 115 | 116 | if (Settings.SerialLogLevel >= LOG_LEVEL_DEBUG_MORE) 117 | Serial.println(postDataStr); 118 | 119 | // This will send the request to the server 120 | client.print(postDataStr); 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 | break; 145 | } 146 | 147 | } 148 | return success; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /Wifi.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Set Wifi AP Mode config 3 | //******************************************************************************** 4 | void WifiAPconfig() 5 | { 6 | // create and store unique AP SSID/PW to prevent ESP from starting AP mode with default SSID and No password! 7 | char ap_ssid[20]; 8 | ap_ssid[0] = 0; 9 | strcpy(ap_ssid, "ESP_"); 10 | sprintf_P(ap_ssid, PSTR("%s%u"), ap_ssid, Settings.Unit); 11 | // setup ssid for AP Mode when needed 12 | WiFi.softAP(ap_ssid, SecuritySettings.WifiAPKey); 13 | // We start in STA mode 14 | WiFi.mode(WIFI_STA); 15 | } 16 | 17 | 18 | //******************************************************************************** 19 | // Set Wifi AP Mode 20 | //******************************************************************************** 21 | void WifiAPMode(boolean state) 22 | { 23 | if (state) 24 | { 25 | AP_Mode = true; 26 | WiFi.mode(WIFI_AP_STA); 27 | } 28 | else 29 | { 30 | AP_Mode = false; 31 | WiFi.mode(WIFI_STA); 32 | } 33 | } 34 | 35 | 36 | //******************************************************************************** 37 | // Connect to Wifi AP 38 | //******************************************************************************** 39 | boolean WifiConnect(byte connectAttempts) 40 | { 41 | String log = ""; 42 | 43 | char hostName[sizeof(Settings.Name)]; 44 | strcpy(hostName,Settings.Name); 45 | for(byte x=0; x< sizeof(hostName); x++) 46 | if (hostName[x] == ' ') 47 | hostName[x] = '-'; 48 | wifi_station_set_hostname(hostName); 49 | 50 | if (Settings.IP[0] != 0 && Settings.IP[0] != 255) 51 | { 52 | char str[20]; 53 | sprintf_P(str, PSTR("%u.%u.%u.%u"), Settings.IP[0], Settings.IP[1], Settings.IP[2], Settings.IP[3]); 54 | log = F("IP : Static IP :"); 55 | log += str; 56 | addLog(LOG_LEVEL_INFO, log); 57 | IPAddress ip = Settings.IP; 58 | IPAddress gw = Settings.Gateway; 59 | IPAddress subnet = Settings.Subnet; 60 | IPAddress dns = Settings.DNS; 61 | WiFi.config(ip, gw, subnet, dns); 62 | } 63 | 64 | 65 | if (WiFi.status() != WL_CONNECTED) 66 | { 67 | if ((SecuritySettings.WifiSSID[0] != 0) && (strcasecmp(SecuritySettings.WifiSSID, "ssid") != 0)) 68 | { 69 | for (byte tryConnect = 1; tryConnect <= connectAttempts; tryConnect++) 70 | { 71 | log = F("WIFI : Connecting... "); 72 | log += tryConnect; 73 | addLog(LOG_LEVEL_INFO, log); 74 | 75 | if (tryConnect == 1) 76 | WiFi.begin(SecuritySettings.WifiSSID, SecuritySettings.WifiKey); 77 | else 78 | WiFi.begin(); 79 | 80 | for (byte x = 0; x < 20; x++) 81 | { 82 | if (WiFi.status() != WL_CONNECTED) 83 | { 84 | delay(500); 85 | } 86 | else 87 | break; 88 | } 89 | if (WiFi.status() == WL_CONNECTED) 90 | { 91 | log = F("WIFI : Connected!"); 92 | addLog(LOG_LEVEL_INFO, log); 93 | break; 94 | } 95 | else 96 | { 97 | log = F("WIFI : Disconnecting!"); 98 | addLog(LOG_LEVEL_INFO, log); 99 | ETS_UART_INTR_DISABLE(); 100 | wifi_station_disconnect(); 101 | ETS_UART_INTR_ENABLE(); 102 | delay(1000); 103 | } 104 | } 105 | 106 | // fix ip if last octet is set 107 | if (Settings.IP_Octet != 0 && Settings.IP_Octet != 255) 108 | { 109 | IPAddress ip = WiFi.localIP(); 110 | IPAddress gw = WiFi.gatewayIP(); 111 | IPAddress subnet = WiFi.subnetMask(); 112 | ip[3] = Settings.IP_Octet; 113 | log = F("IP : Fixed IP :"); 114 | log += ip; 115 | addLog(LOG_LEVEL_INFO, log); 116 | WiFi.config(ip, gw, subnet); 117 | } 118 | } 119 | else 120 | { 121 | log = F("WIFI : No SSID!"); 122 | addLog(LOG_LEVEL_INFO, log); 123 | NC_Count = 1; 124 | WifiAPMode(true); 125 | } 126 | } 127 | } 128 | 129 | 130 | //******************************************************************************** 131 | // Disconnect from Wifi AP 132 | //******************************************************************************** 133 | boolean WifiDisconnect() 134 | { 135 | WiFi.disconnect(); 136 | } 137 | 138 | 139 | //******************************************************************************** 140 | // Scan all Wifi Access Points 141 | //******************************************************************************** 142 | void WifiScan() 143 | { 144 | // Direct Serial is allowed here, since this function will only be called from serial input. 145 | Serial.println(F("WIFI : SSID Scan start")); 146 | int n = WiFi.scanNetworks(); 147 | if (n == 0) 148 | Serial.println(F("WIFI : No networks found")); 149 | else 150 | { 151 | Serial.print(F("WIFI : ")); 152 | Serial.print(n); 153 | Serial.println(F(" networks found")); 154 | for (int i = 0; i < n; ++i) 155 | { 156 | // Print SSID and RSSI for each network found 157 | Serial.print(F("WIFI : ")); 158 | Serial.print(i + 1); 159 | Serial.print(": "); 160 | Serial.print(WiFi.SSID(i)); 161 | Serial.print(" ("); 162 | Serial.print(WiFi.RSSI(i)); 163 | Serial.print(")"); 164 | Serial.println(""); 165 | delay(10); 166 | } 167 | } 168 | Serial.println(""); 169 | } 170 | 171 | 172 | //******************************************************************************** 173 | // Check if we are still connected to a Wifi AP 174 | //******************************************************************************** 175 | void WifiCheck() 176 | { 177 | 178 | if(wifiSetup) 179 | return; 180 | 181 | String log = ""; 182 | 183 | if (WiFi.status() != WL_CONNECTED) 184 | { 185 | NC_Count++; 186 | if (NC_Count > 2) 187 | { 188 | WifiConnect(2); 189 | C_Count=0; 190 | if (WiFi.status() != WL_CONNECTED) 191 | WifiAPMode(true); 192 | NC_Count = 0; 193 | } 194 | } 195 | else 196 | { 197 | C_Count++; 198 | NC_Count = 0; 199 | if (C_Count > 2) // close AP after timeout if a Wifi connection is established... 200 | { 201 | byte wifimode = wifi_get_opmode(); 202 | if (wifimode == 2 || wifimode == 3) //apmode is active 203 | { 204 | WifiAPMode(false); 205 | log = F("WIFI : AP Mode inactive"); 206 | addLog(LOG_LEVEL_INFO, log); 207 | } 208 | } 209 | } 210 | } 211 | 212 | -------------------------------------------------------------------------------- /Controller.ino: -------------------------------------------------------------------------------- 1 | //******************************************************************************** 2 | // Interface for Sending to Controllers 3 | //******************************************************************************** 4 | boolean sendData(struct EventStruct *event) 5 | { 6 | LoadTaskSettings(event->TaskIndex); 7 | if (Settings.UseRules) 8 | createRuleEvents(event->TaskIndex); 9 | 10 | if (Settings.GlobalSync && Settings.TaskDeviceGlobalSync[event->TaskIndex]) 11 | SendUDPTaskData(0, event->TaskIndex, event->TaskIndex); 12 | 13 | if (!Settings.TaskDeviceSendData[event->TaskIndex]) 14 | return false; 15 | 16 | if (Settings.MessageDelay != 0) 17 | { 18 | uint16_t dif = millis() - lastSend; 19 | if (dif < Settings.MessageDelay) 20 | { 21 | uint16_t delayms = Settings.MessageDelay - dif; 22 | char log[30]; 23 | sprintf_P(log, PSTR("HTTP : Delay %u ms"), delayms); 24 | addLog(LOG_LEVEL_DEBUG_MORE, log); 25 | unsigned long timer = millis() + delayms; 26 | while (millis() < timer) 27 | backgroundtasks(); 28 | } 29 | } 30 | 31 | LoadTaskSettings(event->TaskIndex); // could have changed during background tasks. 32 | 33 | if (Settings.Protocol) 34 | { 35 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 36 | CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_SEND, event, dummyString); 37 | } 38 | PluginCall(PLUGIN_EVENT_OUT, event, dummyString); 39 | lastSend = millis(); 40 | } 41 | 42 | 43 | /*********************************************************************************************\ 44 | * Handle incoming MQTT messages 45 | \*********************************************************************************************/ 46 | // handle MQTT messages 47 | void callback(char* c_topic, byte* b_payload, unsigned int length) { 48 | char log[256]; 49 | char c_payload[256]; 50 | strncpy(c_payload,(char*)b_payload,length); 51 | c_payload[length] = 0; 52 | statusLED(true); 53 | 54 | sprintf_P(log, PSTR("%s%s"), "MQTT : Topic: ", c_topic); 55 | addLog(LOG_LEVEL_DEBUG, log); 56 | sprintf_P(log, PSTR("%s%s"), "MQTT : Payload: ", c_payload); 57 | addLog(LOG_LEVEL_DEBUG, log); 58 | 59 | struct EventStruct TempEvent; 60 | TempEvent.String1 = c_topic; 61 | TempEvent.String2 = c_payload; 62 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 63 | CPlugin_ptr[ProtocolIndex](CPLUGIN_PROTOCOL_RECV, &TempEvent, dummyString); 64 | } 65 | 66 | 67 | /*********************************************************************************************\ 68 | * Connect to MQTT message broker 69 | \*********************************************************************************************/ 70 | void MQTTConnect() 71 | { 72 | IPAddress MQTTBrokerIP(Settings.Controller_IP); 73 | MQTTclient.setServer(MQTTBrokerIP, Settings.ControllerPort); 74 | MQTTclient.setCallback(callback); 75 | 76 | // MQTT needs a unique clientname to subscribe to broker 77 | String clientid = "ESPClient"; 78 | clientid += Settings.Unit; 79 | String subscribeTo = ""; 80 | 81 | String LWTTopic = Settings.MQTTsubscribe; 82 | LWTTopic.replace("/#", "/status"); 83 | LWTTopic.replace("%sysname%", Settings.Name); 84 | 85 | for (byte x = 1; x < 3; x++) 86 | { 87 | String log = ""; 88 | boolean MQTTresult = false; 89 | 90 | //boolean connect(const char* id); 91 | //boolean connect(const char* id, const char* user, const char* pass); 92 | //boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 93 | //boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 94 | 95 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 96 | MQTTresult = MQTTclient.connect(clientid.c_str(), SecuritySettings.ControllerUser, SecuritySettings.ControllerPassword, LWTTopic.c_str(), 0, 0, "Connection Lost"); 97 | else 98 | MQTTresult = MQTTclient.connect(clientid.c_str(), LWTTopic.c_str(), 0, 0, "Connection Lost"); 99 | 100 | if (MQTTresult) 101 | { 102 | log = F("MQTT : Connected to broker"); 103 | addLog(LOG_LEVEL_INFO, log); 104 | subscribeTo = Settings.MQTTsubscribe; 105 | subscribeTo.replace("%sysname%", Settings.Name); 106 | MQTTclient.subscribe(subscribeTo.c_str()); 107 | log = F("Subscribed to: "); 108 | log += subscribeTo; 109 | addLog(LOG_LEVEL_INFO, log); 110 | break; // end loop if succesfull 111 | } 112 | else 113 | { 114 | log = F("MQTT : Failed to connected to broker"); 115 | addLog(LOG_LEVEL_ERROR, log); 116 | } 117 | 118 | delay(500); 119 | } 120 | } 121 | 122 | 123 | /*********************************************************************************************\ 124 | * Check connection MQTT message broker 125 | \*********************************************************************************************/ 126 | void MQTTCheck() 127 | { 128 | byte ProtocolIndex = getProtocolIndex(Settings.Protocol); 129 | if (Protocol[ProtocolIndex].usesMQTT) 130 | if (!MQTTclient.connected()) 131 | { 132 | String log = F("MQTT : Connection lost"); 133 | addLog(LOG_LEVEL_ERROR, log); 134 | connectionFailures += 2; 135 | MQTTclient.disconnect(); 136 | delay(1000); 137 | MQTTConnect(); 138 | } 139 | else if (connectionFailures) 140 | connectionFailures--; 141 | } 142 | 143 | 144 | /*********************************************************************************************\ 145 | * Send status info to request source 146 | \*********************************************************************************************/ 147 | 148 | void SendStatus(byte source, String status) 149 | { 150 | switch(source) 151 | { 152 | case VALUE_SOURCE_HTTP: 153 | if (printToWeb) 154 | printWebString += status; 155 | break; 156 | case VALUE_SOURCE_MQTT: 157 | MQTTStatus(status); 158 | break; 159 | case VALUE_SOURCE_SERIAL: 160 | Serial.println(status); 161 | break; 162 | } 163 | } 164 | 165 | 166 | /*********************************************************************************************\ 167 | * Send status info back to channel where request came from 168 | \*********************************************************************************************/ 169 | void MQTTStatus(String& status) 170 | { 171 | String pubname = Settings.MQTTsubscribe; 172 | pubname.replace("/#", "/status"); 173 | pubname.replace("%sysname%", Settings.Name); 174 | MQTTclient.publish(pubname.c_str(), status.c_str(),Settings.MQTTRetainFlag); 175 | } 176 | 177 | 178 | 179 | -------------------------------------------------------------------------------- /_P013_HCSR04.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 013: HC-SR04 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_013 6 | #define PLUGIN_ID_013 13 7 | #define PLUGIN_NAME_013 "Ultrasonic Sensor - HC-SR04" 8 | #define PLUGIN_VALUENAME1_013 "Distance" 9 | 10 | void Plugin_013_interrupt() ICACHE_RAM_ATTR; 11 | 12 | boolean Plugin_013_init = false; 13 | volatile unsigned long Plugin_013_timer = 0; 14 | volatile unsigned long Plugin_013_state = 0; 15 | byte Plugin_013_TRIG_Pin = 0; 16 | byte Plugin_013_IRQ_Pin = 0; 17 | 18 | boolean Plugin_013(byte function, struct EventStruct *event, String& string) 19 | { 20 | static byte switchstate[TASKS_MAX]; 21 | boolean success = false; 22 | 23 | switch (function) 24 | { 25 | case PLUGIN_DEVICE_ADD: 26 | { 27 | Device[++deviceCount].Number = PLUGIN_ID_013; 28 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 29 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 30 | Device[deviceCount].Ports = 0; 31 | Device[deviceCount].PullUpOption = false; 32 | Device[deviceCount].InverseLogicOption = false; 33 | Device[deviceCount].FormulaOption = false; 34 | Device[deviceCount].ValueCount = 1; 35 | Device[deviceCount].SendDataOption = true; 36 | Device[deviceCount].TimerOption = true; 37 | Device[deviceCount].GlobalSyncOption = true; 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICENAME: 42 | { 43 | string = F(PLUGIN_NAME_013); 44 | break; 45 | } 46 | 47 | case PLUGIN_GET_DEVICEVALUENAMES: 48 | { 49 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_013)); 50 | break; 51 | } 52 | 53 | 54 | case PLUGIN_WEBFORM_LOAD: 55 | { 56 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 57 | String options[2]; 58 | options[0] = F("Value"); 59 | options[1] = F("State"); 60 | int optionValues[2]; 61 | optionValues[0] = 1; 62 | optionValues[1] = 2; 63 | string += F("Mode:"); 76 | 77 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 78 | { 79 | char tmpString[128]; 80 | sprintf_P(tmpString, PSTR("Threshold:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); 81 | string += tmpString; 82 | } 83 | success = true; 84 | break; 85 | } 86 | 87 | case PLUGIN_WEBFORM_SAVE: 88 | { 89 | String plugin1 = WebServer.arg("plugin_013_mode"); 90 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 91 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 92 | { 93 | String plugin2 = WebServer.arg("plugin_013_threshold"); 94 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 95 | } 96 | success = true; 97 | break; 98 | } 99 | 100 | case PLUGIN_INIT: 101 | { 102 | Plugin_013_init = true; 103 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); 104 | pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); 105 | Plugin_013_IRQ_Pin = Settings.TaskDevicePin2[event->TaskIndex]; 106 | attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_013_interrupt, CHANGE); 107 | success = true; 108 | break; 109 | } 110 | 111 | case PLUGIN_READ: // If we select value mode, read and send the value based on global timer 112 | { 113 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1) 114 | { 115 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 116 | float value = Plugin_013_read(); 117 | String log = F("SR04 : Distance: "); 118 | if (value != -1) 119 | { 120 | UserVar[event->BaseVarIndex] = (float)Plugin_013_timer / 58; 121 | log += UserVar[event->BaseVarIndex]; 122 | success = true; 123 | } 124 | else 125 | log += F("SR04 : Distance: No reading!"); 126 | 127 | addLog(LOG_LEVEL_INFO,log); 128 | } 129 | break; 130 | } 131 | 132 | case PLUGIN_TEN_PER_SECOND: // If we select state mode, do more frequent checks and send only state changes 133 | { 134 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) 135 | { 136 | Plugin_013_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 137 | byte state = 0; 138 | float value = Plugin_013_read(); 139 | if (value != -1) 140 | { 141 | if (value < Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 142 | state = 1; 143 | if (state != switchstate[event->TaskIndex]) 144 | { 145 | String log = F("SR04 : State "); 146 | log += state; 147 | addLog(LOG_LEVEL_INFO,log); 148 | switchstate[event->TaskIndex] = state; 149 | UserVar[event->BaseVarIndex] = state; 150 | event->sensorType = SENSOR_TYPE_SWITCH; 151 | sendData(event); 152 | } 153 | } 154 | } 155 | success = true; 156 | break; 157 | } 158 | } 159 | return success; 160 | } 161 | 162 | /*********************************************************************/ 163 | float Plugin_013_read() 164 | /*********************************************************************/ 165 | { 166 | float value = -1; 167 | Plugin_013_timer = 0; 168 | Plugin_013_state = 0; 169 | noInterrupts(); 170 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 171 | delayMicroseconds(2); 172 | digitalWrite(Plugin_013_TRIG_Pin, HIGH); 173 | delayMicroseconds(10); 174 | digitalWrite(Plugin_013_TRIG_Pin, LOW); 175 | interrupts(); 176 | 177 | delay(25); // wait for measurement to finish (max 400 cm * 58 uSec = 23uSec) 178 | if (Plugin_013_state == 2) 179 | { 180 | value = (float)Plugin_013_timer / 58; 181 | } 182 | return value; 183 | } 184 | 185 | /*********************************************************************/ 186 | void Plugin_013_interrupt() 187 | /*********************************************************************/ 188 | { 189 | byte pinState = digitalRead(Plugin_013_IRQ_Pin); 190 | if (pinState == 1) // Start of pulse 191 | { 192 | Plugin_013_state = 1; 193 | Plugin_013_timer = micros(); 194 | } 195 | else // End of pulse, calculate timelapse between start & end 196 | { 197 | Plugin_013_state = 2; 198 | Plugin_013_timer = micros() - Plugin_013_timer; 199 | } 200 | } 201 | 202 | -------------------------------------------------------------------------------- /_C009.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 009: FHEM HTTP ########################################## 3 | //####################################################################################################### 4 | 5 | /******************************************************************************* 6 | * Modified version of "Domoticz HTTP CPLUGIN" 7 | * Copyright 2016 dev0 (https://forum.fhem.de/index.php?action=profile;u=7465) 8 | * Release notes: 9 | - v1.0 10 | - changed switch and dimmer setreading cmds 11 | - v1.01 12 | - added json content to http requests 13 | - v1.02 14 | - some optimizations as requested by mvdbro 15 | - fixed JSON TaskDeviceValueDecimals handling 16 | - ArduinoJson Library v5.6.4 required (as used by stable R120) 17 | - parse for HTTP errors 400, 401 18 | - moved on/off translation for SENSOR_TYPE_SWITCH/DIMMER to FHEM module 19 | /******************************************************************************/ 20 | 21 | #define CPLUGIN_009 22 | #define CPLUGIN_ID_009 9 23 | #define CPLUGIN_NAME_009 "FHEM HTTP" 24 | 25 | boolean CPlugin_009(byte function, struct EventStruct *event, String& string) 26 | { 27 | boolean success = false; 28 | 29 | switch (function) 30 | { 31 | case CPLUGIN_PROTOCOL_ADD: 32 | { 33 | Protocol[++protocolCount].Number = CPLUGIN_ID_009; 34 | Protocol[protocolCount].usesMQTT = false; 35 | Protocol[protocolCount].usesTemplate = false; 36 | Protocol[protocolCount].usesAccount = true; 37 | Protocol[protocolCount].usesPassword = true; 38 | Protocol[protocolCount].defaultPort = 8383; 39 | break; 40 | } 41 | 42 | case CPLUGIN_GET_DEVICENAME: 43 | { 44 | string = F(CPLUGIN_NAME_009); 45 | break; 46 | } 47 | 48 | case CPLUGIN_PROTOCOL_SEND: 49 | { 50 | 51 | if (ExtraTaskSettings.TaskDeviceValueNames[0][0] == 0) 52 | PluginCall(PLUGIN_GET_DEVICEVALUENAMES, event, dummyString); 53 | 54 | // We now create a URI for the request 55 | String url = F("/fhem?cmd="); 56 | 57 | // Create json root object 58 | DynamicJsonBuffer jsonBuffer; 59 | JsonObject& root = jsonBuffer.createObject(); 60 | root["module"] = "ESPEasy"; 61 | root["version"] = "1.02"; 62 | 63 | // Create nested objects 64 | JsonObject& data = root.createNestedObject("data"); 65 | JsonObject& ESP = data.createNestedObject("ESP"); 66 | ESP["name"] = Settings.Name; 67 | ESP["unit"] = Settings.Unit; 68 | ESP["version"] = Settings.Version; 69 | ESP["build"] = Settings.Build; 70 | ESP["sleep"] = Settings.deepSleep; 71 | 72 | // embed IP, important if there is NAT/PAT 73 | char ipStr[20]; 74 | IPAddress ip = WiFi.localIP(); 75 | sprintf(ipStr, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); 76 | ESP["ip"] = ipStr; 77 | 78 | // Create nested SENSOR json object 79 | JsonObject& SENSOR = data.createNestedObject("SENSOR"); 80 | byte valueCount = getValueCountFromSensorType(event->sensorType); 81 | char itemNames[valueCount][2]; 82 | for (byte x = 0; x < valueCount; x++) 83 | { 84 | String s; 85 | url += F("setreading%20"); 86 | url += Settings.Name; 87 | url += F("%20"); 88 | url += ExtraTaskSettings.TaskDeviceValueNames[x]; 89 | url += F("%20"); 90 | 91 | // Each sensor value get an own object (0..n) 92 | sprintf(itemNames[x],"%d",x); 93 | JsonObject& val = SENSOR.createNestedObject(itemNames[x]); 94 | val["deviceName"] = ExtraTaskSettings.TaskDeviceName; 95 | val["valueName"] = ExtraTaskSettings.TaskDeviceValueNames[x]; 96 | val["type"] = event->sensorType; 97 | 98 | if (event->sensorType == SENSOR_TYPE_LONG) { 99 | s = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 100 | url += s; 101 | val["value"] = s; 102 | 103 | } else { // All other sensor types 104 | s = toString(UserVar[event->BaseVarIndex + x], ExtraTaskSettings.TaskDeviceValueDecimals[x]); 105 | url += s; 106 | val["value"] = s; 107 | } 108 | 109 | // Split FHEM commands by ";" 110 | if (x < valueCount-1) 111 | url += F("%3B"); 112 | } 113 | 114 | // Create json buffer 115 | char buffer[root.measureLength() +1]; 116 | root.printTo(buffer, sizeof(buffer)); 117 | // Push data to server 118 | FHEMHTTPsend(url, buffer); 119 | break; 120 | } 121 | } 122 | return success; 123 | } 124 | 125 | 126 | //******************************************************************************** 127 | // FHEM HTTP request 128 | //******************************************************************************** 129 | boolean FHEMHTTPsend(String url, char* buffer) 130 | { 131 | boolean success = false; 132 | 133 | String authHeader = ""; 134 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) { 135 | base64 encoder; 136 | String auth = SecuritySettings.ControllerUser; 137 | auth += ":"; 138 | auth += SecuritySettings.ControllerPassword; 139 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 140 | } 141 | 142 | char log[80]; 143 | url.toCharArray(log, 80); 144 | addLog(LOG_LEVEL_DEBUG_MORE, log); 145 | 146 | char host[20]; 147 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 148 | 149 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 150 | addLog(LOG_LEVEL_DEBUG, log); 151 | 152 | // Use WiFiClient class to create TCP connections 153 | WiFiClient client; 154 | if (!client.connect(host, Settings.ControllerPort)) { 155 | connectionFailures++; 156 | strcpy_P(log, PSTR("HTTP : connection failed")); 157 | addLog(LOG_LEVEL_ERROR, log); 158 | return false; 159 | } 160 | 161 | statusLED(true); 162 | if (connectionFailures) 163 | connectionFailures--; 164 | 165 | // This will send the request to the server 166 | int len = strlen(buffer); 167 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 168 | "Content-Length: "+ len + "\r\n" + 169 | "Host: " + host + "\r\n" + authHeader + 170 | "Connection: close\r\n\r\n" 171 | + buffer); 172 | 173 | unsigned long timer = millis() + 200; 174 | while (!client.available() && millis() < timer) 175 | delay(1); 176 | 177 | // Read all the lines of the reply from server and print them to Serial 178 | while (client.available()) { 179 | String line = client.readStringUntil('\n'); 180 | String helper = line; 181 | line.toCharArray(log, 80); 182 | addLog(LOG_LEVEL_DEBUG_MORE, log); 183 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") { 184 | strcpy_P(log, PSTR("HTTP : Success")); 185 | success = true; 186 | } 187 | else if (line.substring(0, 24) == "HTTP/1.1 400 Bad Request") { 188 | strcpy_P(log, PSTR("HTTP : Unauthorized")); 189 | } 190 | else if (line.substring(0, 25) == "HTTP/1.1 401 Unauthorized") { 191 | strcpy_P(log, PSTR("HTTP : Unauthorized")); 192 | } 193 | addLog(LOG_LEVEL_DEBUG, log); 194 | delay(1); 195 | } 196 | strcpy_P(log, PSTR("HTTP : closing connection")); 197 | addLog(LOG_LEVEL_DEBUG, log); 198 | client.flush(); 199 | client.stop(); 200 | } 201 | -------------------------------------------------------------------------------- /_P025_ADS1115.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 025: ADS1115 I2C 0x48) ############################################### 3 | //####################################################################################################### 4 | 5 | // MyMessage *msgAnalog025; // Mysensors 6 | 7 | #define PLUGIN_025 8 | #define PLUGIN_ID_025 25 9 | #define PLUGIN_NAME_025 "Analog input - ADS1115" 10 | #define PLUGIN_VALUENAME1_025 "Analog" 11 | 12 | boolean Plugin_025_init = false; 13 | // byte Plugin_Switch_Pin = 0; 14 | 15 | static uint16_t readRegister025(uint8_t i2cAddress, uint8_t reg) { 16 | Wire.beginTransmission(i2cAddress); 17 | Wire.write((0x00)); 18 | Wire.endTransmission(); 19 | Wire.requestFrom(i2cAddress, (uint8_t)2); 20 | return ((Wire.read() << 8) | Wire.read()); 21 | } 22 | 23 | boolean Plugin_025(byte function, struct EventStruct *event, String& string) 24 | { 25 | boolean success = false; 26 | static byte portValue = 0; 27 | switch (function) 28 | { 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_025; 32 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 33 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 34 | Device[deviceCount].Ports = 4; 35 | Device[deviceCount].PullUpOption = false; 36 | Device[deviceCount].InverseLogicOption = false; 37 | Device[deviceCount].FormulaOption = true; 38 | Device[deviceCount].ValueCount = 1; 39 | Device[deviceCount].SendDataOption = true; 40 | Device[deviceCount].TimerOption = true; 41 | Device[deviceCount].GlobalSyncOption = true; 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICENAME: 46 | { 47 | string = F(PLUGIN_NAME_025); 48 | break; 49 | } 50 | 51 | case PLUGIN_GET_DEVICEVALUENAMES: 52 | { 53 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_025)); 54 | break; 55 | } 56 | 57 | case PLUGIN_WEBFORM_LOAD: 58 | { 59 | #define ADS1115_GAIN_OPTION 6 60 | 61 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 62 | String options[ADS1115_GAIN_OPTION]; 63 | uint optionValues[ADS1115_GAIN_OPTION]; 64 | optionValues[0] = (0x00); 65 | options[0] = F("2/3x gain 6.144V 0.1875mV"); 66 | optionValues[1] = (0x02); 67 | options[1] = F("1x gain 4.096V 0.125mV"); 68 | optionValues[2] = (0x04); 69 | options[2] = F("2x gain 2.048V 0.0625mV"); 70 | optionValues[3] = (0x06); 71 | options[3] = F("4x gain 1.024V 0.03125mV"); 72 | optionValues[4] = (0x08); 73 | options[4] = F("8x gain 0.512V 0.015625mV"); 74 | optionValues[5] = (0x0A); 75 | options[5] = F("16x gain 0.256V 0.0078125mV"); 76 | 77 | string += F("Gain:"); 90 | 91 | success = true; 92 | break; 93 | } 94 | 95 | case PLUGIN_WEBFORM_SAVE: 96 | { 97 | String plugin1 = WebServer.arg("plugin_025_gain"); 98 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 99 | Plugin_025_init = false; // Force device setup next time 100 | success = true; 101 | break; 102 | } 103 | 104 | case PLUGIN_INIT: 105 | { 106 | Plugin_025_init = true; 107 | // Plugin_Switch_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 108 | // if (!msgAnalog025) //Mysensors 109 | // msgDust025 = new MyMessage(event->BaseVarIndex, V_LEVEL); //Mysensors 110 | // present(event->BaseVarIndex, S_DUST); //Mysensors 111 | // Serial.print("Present ADS1115: "); // Mysensors 112 | // Serial.println(event->BaseVarIndex); // Mysensors 113 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 114 | // { 115 | // pinMode(Plugin_Switch_Pin, OUTPUT); 116 | // digitalWrite(Plugin_Switch_Pin, HIGH); 117 | // } 118 | success = true; 119 | break; 120 | } 121 | 122 | case PLUGIN_READ: 123 | { 124 | uint8_t m_gain = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 125 | // noInterrupts(); 126 | int value; 127 | value = 0; 128 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 129 | // { 130 | // Plugin_Switch_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 131 | // digitalWrite(Plugin_Switch_Pin, LOW); 132 | // delayMicroseconds(280); 133 | // } 134 | byte unit = (Settings.TaskDevicePort[event->TaskIndex] - 1) / 4; 135 | byte port = Settings.TaskDevicePort[event->TaskIndex] - (unit * 4); 136 | uint8_t address = 0x48 + unit; 137 | // get the current pin value 138 | 139 | uint16_t config = (0x0003) | // Disable the comparator (default val) 140 | (0x0000) | // Non-latching (default val) 141 | (0x0000) | // Alert/Rdy active low (default val) 142 | (0x0000) | // Traditional comparator (default val) 143 | (0x0080) | // 1600 samples per second (default) 144 | (0x0100) ; // Single-shot mode (default) 145 | 146 | // m_Gain = (0x0000); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) 147 | // m_Gain = (0x0200); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV 148 | // m_Gain = (0x0400); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV 149 | // m_Gain = (0x0600); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV 150 | // m_Gain = (0x0800); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV 151 | // m_Gain = (0x0A00); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV 152 | // config |= m_gain; 153 | // config |= (0x0000); 154 | switch (m_gain) 155 | { 156 | case (0x00): 157 | config |= (0x0000); 158 | break; 159 | case (0x02): 160 | config |= (0x0200); 161 | break; 162 | case (0x04): 163 | config |= (0x0400); 164 | break; 165 | case (0x06): 166 | config |= (0x0600); 167 | break; 168 | case (0x08): 169 | config |= (0x0800); 170 | break; 171 | case (0x0A): 172 | config |= (0x0A00); 173 | break; 174 | } 175 | switch (port) 176 | { 177 | case (0): 178 | config |= (0x4000); 179 | break; 180 | case (1): 181 | config |= (0x5000); 182 | break; 183 | case (2): 184 | config |= (0x6000); 185 | break; 186 | case (3): 187 | config |= (0x7000); 188 | break; 189 | } 190 | config |= (0x8000); 191 | Wire.beginTransmission(address); 192 | Wire.write((uint8_t)(0x01)); 193 | Wire.write((uint8_t)(config>>8)); 194 | Wire.write((uint8_t)(config & 0xFF)); 195 | Wire.endTransmission(); 196 | delay(8); 197 | UserVar[event->BaseVarIndex] = (float) readRegister025((address), (0x00)) ; 198 | String log = F("ADS1115 : Analog value: "); 199 | log += UserVar[event->BaseVarIndex]; 200 | // send(msgDust025->set(UserVar[event->BaseVarIndex], 1)); // Mysensors 201 | addLog(LOG_LEVEL_INFO,log); 202 | success = true; 203 | // if (Settings.TaskDevicePin1[event->TaskIndex] != -1) 204 | // { 205 | // delayMicroseconds(40); 206 | // digitalWrite(Plugin_Switch_Pin, HIGH); 207 | // } 208 | // interrupts(); 209 | break; 210 | } 211 | } 212 | return success; 213 | } 214 | -------------------------------------------------------------------------------- /_P005_DHT.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 005: Temperature and Humidity sensor DHT 11/22 ######################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_005 6 | #define PLUGIN_ID_005 5 7 | #define PLUGIN_NAME_005 "Temperature & Humidity - DHT" 8 | #define PLUGIN_VALUENAME1_005 "Temperature" 9 | #define PLUGIN_VALUENAME2_005 "Humidity" 10 | 11 | uint8_t Plugin_005_DHT_Pin; 12 | 13 | boolean Plugin_005(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_005; 22 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 23 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 24 | Device[deviceCount].Ports = 0; 25 | Device[deviceCount].PullUpOption = false; 26 | Device[deviceCount].InverseLogicOption = false; 27 | Device[deviceCount].FormulaOption = true; 28 | Device[deviceCount].ValueCount = 2; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_005); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_005)); 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_005)); 45 | break; 46 | } 47 | 48 | case PLUGIN_WEBFORM_LOAD: 49 | { 50 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 51 | String options[3]; 52 | options[0] = F("DHT 11"); 53 | options[1] = F("DHT 22"); 54 | options[2] = F("DHT 12"); 55 | int optionValues[3]; 56 | optionValues[0] = 11; 57 | optionValues[1] = 22; 58 | optionValues[2] = 12; 59 | string += F("DHT Type:"); 72 | 73 | success = true; 74 | break; 75 | } 76 | 77 | case PLUGIN_WEBFORM_SAVE: 78 | { 79 | String plugin1 = WebServer.arg("plugin_005_dhttype"); 80 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 81 | success = true; 82 | break; 83 | } 84 | 85 | case PLUGIN_READ: 86 | { 87 | byte dht_dat[5]; 88 | byte dht_in; 89 | byte i; 90 | byte Retry = 0; 91 | boolean error = false; 92 | 93 | byte Par3 = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 94 | Plugin_005_DHT_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 95 | 96 | pinMode(Plugin_005_DHT_Pin, OUTPUT); 97 | // DHT start condition, pull-down i/o pin for 18ms 98 | digitalWrite(Plugin_005_DHT_Pin, LOW); // Pull low 99 | delay(18); 100 | digitalWrite(Plugin_005_DHT_Pin, HIGH); // Pull high 101 | delayMicroseconds(20); // was 40 102 | pinMode(Plugin_005_DHT_Pin, INPUT); // change pin to input 103 | delayMicroseconds(10); 104 | 105 | dht_in = digitalRead(Plugin_005_DHT_Pin); 106 | if (!dht_in) 107 | { 108 | delayMicroseconds(80); 109 | dht_in = digitalRead(Plugin_005_DHT_Pin); 110 | if (dht_in) 111 | { 112 | delayMicroseconds(80); // now ready for data reception 113 | for (i = 0; i < 5; i++) 114 | { 115 | byte data = Plugin_005_read_dht_dat(); 116 | if (data != -1) 117 | dht_dat[i] = data; 118 | else 119 | { 120 | addLog(LOG_LEVEL_ERROR, (char*)"DHT : protocol timeout!"); 121 | error = true; 122 | } 123 | } 124 | 125 | if (!error) 126 | { 127 | 128 | // Checksum calculation is a Rollover Checksum by design! 129 | byte dht_check_sum = dht_dat[0] + dht_dat[1] + dht_dat[2] + dht_dat[3]; // check check_sum 130 | 131 | if (dht_dat[4] == dht_check_sum) 132 | { 133 | float temperature = NAN; 134 | float humidity = NAN; 135 | 136 | if (Par3 == 11) 137 | { 138 | temperature = float(dht_dat[2]); // Temperature 139 | humidity = float(dht_dat[0]); // Humidity 140 | } 141 | else if (Par3 == 12) 142 | { 143 | temperature = float(dht_dat[2]*10 + (dht_dat[3] & 0x7f)) / 10.0; // Temperature 144 | if (dht_dat[3] & 0x80) { temperature = -temperature; } // Negative temperature 145 | humidity = float(dht_dat[0]*10+dht_dat[1]) / 10.0; // Humidity 146 | } 147 | 148 | if (Par3 == 22) 149 | { 150 | if (dht_dat[2] & 0x80) // negative temperature 151 | temperature = -0.1 * word(dht_dat[2] & 0x7F, dht_dat[3]); 152 | else 153 | temperature = 0.1 * word(dht_dat[2], dht_dat[3]); 154 | humidity = word(dht_dat[0], dht_dat[1]) * 0.1; // Humidity 155 | } 156 | if (temperature != NAN || humidity != NAN) // According to negated original if, maybe use && instead? 157 | { 158 | UserVar[event->BaseVarIndex] = temperature; 159 | UserVar[event->BaseVarIndex + 1] = humidity; 160 | String log = F("DHT : Temperature: "); 161 | log += UserVar[event->BaseVarIndex]; 162 | addLog(LOG_LEVEL_INFO, log); 163 | log = F("DHT : Humidity: "); 164 | log += UserVar[event->BaseVarIndex + 1]; 165 | addLog(LOG_LEVEL_INFO, log); 166 | success = true; 167 | } 168 | } // checksum 169 | } // error 170 | } // dht 171 | } // !dht 172 | if(!success) 173 | { 174 | String log = F("DHT : No reading!"); 175 | addLog(LOG_LEVEL_INFO, log); 176 | UserVar[event->BaseVarIndex] = NAN; 177 | UserVar[event->BaseVarIndex + 1] = NAN; 178 | } 179 | break; 180 | } 181 | } 182 | return success; 183 | } 184 | 185 | 186 | /*********************************************************************************************\ 187 | * DHT sub to get an 8 bit value from the receiving bitstream 188 | \*********************************************************************************************/ 189 | int Plugin_005_read_dht_dat(void) 190 | { 191 | byte i = 0; 192 | byte result = 0; 193 | byte counter = 0; 194 | //noInterrupts(); 195 | for (i = 0; i < 8; i++) 196 | { 197 | while ((!digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 198 | { 199 | delayMicroseconds(1); 200 | counter++; 201 | } 202 | if (counter >= 100) 203 | { 204 | //interrupts(); 205 | return -1; 206 | } 207 | delayMicroseconds(30); 208 | if (digitalRead(Plugin_005_DHT_Pin)) 209 | result |= (1 << (7 - i)); 210 | counter = 0; 211 | while ((digitalRead(Plugin_005_DHT_Pin)) && (counter < 100)) 212 | { 213 | delayMicroseconds(1); 214 | counter++; 215 | } 216 | if (counter >= 100) 217 | { 218 | //interrupts(); 219 | return -1; 220 | } 221 | } 222 | //interrupts(); 223 | return result; 224 | } 225 | 226 | -------------------------------------------------------------------------------- /_P031_SHT1X.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################### Plugin 031: SHT10/SHT11/SHT15 Temp/Humidity Sensor ############################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_031 6 | #define PLUGIN_ID_031 31 7 | #define PLUGIN_NAME_031 "Temperature & Humidity - SHT1X" 8 | #define PLUGIN_VALUENAME1_031 "Temperature" 9 | #define PLUGIN_VALUENAME2_031 "Humidity" 10 | 11 | boolean Plugin_031_init = false; 12 | byte Plugin_031_DATA_Pin = 0; 13 | byte Plugin_031_CLOCK_Pin = 0; 14 | int input_mode; 15 | 16 | enum { 17 | SHT1X_CMD_MEASURE_TEMP = B00000011, 18 | SHT1X_CMD_MEASURE_RH = B00000101, 19 | SHT1X_CMD_READ_STATUS = B00000111, 20 | SHT1X_CMD_SOFT_RESET = B00011110 21 | }; 22 | 23 | boolean Plugin_031(byte function, struct EventStruct *event, String& string) 24 | { 25 | boolean success = false; 26 | 27 | switch (function) 28 | { 29 | case PLUGIN_DEVICE_ADD: 30 | { 31 | Device[++deviceCount].Number = PLUGIN_ID_031; 32 | Device[deviceCount].Type = DEVICE_TYPE_DUAL; 33 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_HUM; 34 | Device[deviceCount].Ports = 0; 35 | Device[deviceCount].PullUpOption = true; 36 | Device[deviceCount].InverseLogicOption = false; 37 | Device[deviceCount].FormulaOption = true; 38 | Device[deviceCount].ValueCount = 2; 39 | Device[deviceCount].SendDataOption = true; 40 | Device[deviceCount].TimerOption = true; 41 | Device[deviceCount].GlobalSyncOption = true; 42 | break; 43 | } 44 | 45 | case PLUGIN_GET_DEVICENAME: 46 | { 47 | string = F(PLUGIN_NAME_031); 48 | break; 49 | } 50 | 51 | case PLUGIN_GET_DEVICEVALUENAMES: 52 | { 53 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_031)); 54 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_031)); 55 | break; 56 | } 57 | 58 | case PLUGIN_INIT: 59 | { 60 | Plugin_031_init = true; 61 | Plugin_031_DATA_Pin = Settings.TaskDevicePin1[event->TaskIndex]; 62 | Plugin_031_CLOCK_Pin = Settings.TaskDevicePin2[event->TaskIndex]; 63 | if (Settings.TaskDevicePin1PullUp[event->TaskIndex]) { 64 | input_mode = INPUT_PULLUP; 65 | String log = F("SHT1X: Setting PullUp on pin "); 66 | log += String(Plugin_031_DATA_Pin); 67 | addLog(LOG_LEVEL_DEBUG, log); 68 | } 69 | else { 70 | input_mode = INPUT; 71 | } 72 | pinMode(Plugin_031_DATA_Pin, input_mode); /* Keep Hi-Z except when sending data */ 73 | pinMode(Plugin_031_CLOCK_Pin, OUTPUT); 74 | Plugin_031_reset(); 75 | byte status = Plugin_031_readStatus(); 76 | String log = F("SHT1X : Status byte: "); 77 | log += String(status, HEX); 78 | log += F(" - resolution: "); 79 | log += (status & 1 ? "low" : "high"); 80 | log += F(" reload from OTP: "); 81 | log += ((status >> 1) & 1 ? "yes" : "no"); 82 | log += F(", heater: "); 83 | log += ((status >> 2) & 1 ? "on" : "off"); 84 | addLog(LOG_LEVEL_DEBUG, log); 85 | success = true; 86 | break; 87 | } 88 | 89 | case PLUGIN_READ: 90 | { 91 | if (!Plugin_031_init) { 92 | String log = F("SHT1X : not yet initialized!"); 93 | addLog(LOG_LEVEL_ERROR, log); 94 | break; 95 | } 96 | UserVar[event->BaseVarIndex] = Plugin_031_readTemperature(); 97 | UserVar[event->BaseVarIndex+1] = Plugin_031_readRelHumidity(UserVar[event->BaseVarIndex]); 98 | success = true; 99 | break; 100 | } 101 | } 102 | return success; 103 | } 104 | 105 | float Plugin_031_readTemperature() 106 | { 107 | float tempRaw, tempC; 108 | 109 | Plugin_031_sendCommand(SHT1X_CMD_MEASURE_TEMP); 110 | Plugin_031_awaitResult(); 111 | tempRaw = Plugin_031_readData(16); 112 | 113 | // Temperature conversion coefficients from SHT1X datasheet for version 4 114 | const float d1 = -39.7; // 3.5V 115 | const float d2 = 0.01; // 14-bit 116 | 117 | tempC = d1 + (tempRaw * d2); 118 | 119 | String log = F("SHT1X : Read temperature (raw): "); 120 | log += String(tempRaw); 121 | log += " (Celcius): "; 122 | log += String(tempC); 123 | addLog(LOG_LEVEL_DEBUG, log); 124 | 125 | return tempC; 126 | } 127 | 128 | float Plugin_031_readRelHumidity(float tempC) 129 | { 130 | float raw, rhLinear, rhTrue; 131 | 132 | Plugin_031_sendCommand(SHT1X_CMD_MEASURE_RH); 133 | Plugin_031_awaitResult(); 134 | raw = Plugin_031_readData(16); 135 | 136 | // Temperature conversion coefficients from SHT1X datasheet for version 4 137 | const float c1 = -2.0468; 138 | const float c2 = 0.0367; 139 | const float c3 = -1.5955E-6; 140 | const float t1 = 0.01; 141 | const float t2 = 0.00008; 142 | 143 | rhLinear = c1 + c2 * raw + c3 * raw * raw; 144 | rhTrue = (tempC - 25) * (t1 + t2 * raw) + rhLinear; 145 | 146 | String log = F("SHT1X : Read humidity (raw): "); 147 | log += String(raw); 148 | log += " (Linear): "; 149 | log += String(rhLinear); 150 | log += " (True): "; 151 | log += String(rhTrue); 152 | addLog(LOG_LEVEL_DEBUG, log); 153 | 154 | return rhTrue; 155 | } 156 | 157 | 158 | void Plugin_031_reset() 159 | { 160 | delay(11); 161 | for (int i=0; i<9; i++) { 162 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 163 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 164 | } 165 | Plugin_031_sendCommand(SHT1X_CMD_SOFT_RESET); 166 | delay(11); 167 | } 168 | 169 | byte Plugin_031_readStatus() 170 | { 171 | Plugin_031_sendCommand(SHT1X_CMD_READ_STATUS); 172 | return Plugin_031_readData(8); 173 | } 174 | 175 | void Plugin_031_sendCommand(const byte cmd) 176 | { 177 | pinMode(Plugin_031_DATA_Pin, OUTPUT); 178 | 179 | // Transmission Start sequence 180 | digitalWrite(Plugin_031_DATA_Pin, HIGH); 181 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 182 | digitalWrite(Plugin_031_DATA_Pin, LOW); 183 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 184 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 185 | digitalWrite(Plugin_031_DATA_Pin, HIGH); 186 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 187 | 188 | // Send the command (address must be 000b) 189 | shiftOut(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, MSBFIRST, cmd); 190 | 191 | // Wait for ACK 192 | bool ackerror = false; 193 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 194 | pinMode(Plugin_031_DATA_Pin, input_mode); 195 | if (digitalRead(Plugin_031_DATA_Pin) != LOW) ackerror = true; 196 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 197 | 198 | if (cmd == SHT1X_CMD_MEASURE_TEMP || cmd == SHT1X_CMD_MEASURE_RH) { 199 | delayMicroseconds(1); /* Give the sensor time to release the data line */ 200 | if (digitalRead(Plugin_031_DATA_Pin) != HIGH) ackerror = true; 201 | } 202 | 203 | if (ackerror) { 204 | String log = F("SHT1X : Sensor did not ACK command"); 205 | addLog(LOG_LEVEL_ERROR, log); 206 | } 207 | } 208 | 209 | void Plugin_031_awaitResult() 210 | { 211 | // Maximum 320ms for 14 bit measurement 212 | for (int i=0; i<16; i++) { 213 | if (digitalRead(Plugin_031_DATA_Pin) == LOW) return; 214 | delay(20); 215 | } 216 | if (digitalRead(Plugin_031_DATA_Pin) != LOW) { 217 | String log = F("SHT1X : Data not ready"); 218 | addLog(LOG_LEVEL_ERROR, log); 219 | } 220 | } 221 | 222 | int Plugin_031_readData(const int bits) 223 | { 224 | int val = 0; 225 | 226 | if (bits == 16) { 227 | // Read most significant byte 228 | val = shiftIn(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, 8); 229 | val <<= 8; 230 | 231 | // Send ACK 232 | pinMode(Plugin_031_DATA_Pin, OUTPUT); 233 | digitalWrite(Plugin_031_DATA_Pin, LOW); 234 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 235 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 236 | pinMode(Plugin_031_DATA_Pin, input_mode); 237 | } 238 | 239 | // Read least significant byte 240 | val |= shiftIn(Plugin_031_DATA_Pin, Plugin_031_CLOCK_Pin, 8); 241 | 242 | // Keep DATA pin high to skip CRC 243 | digitalWrite(Plugin_031_CLOCK_Pin, HIGH); 244 | digitalWrite(Plugin_031_CLOCK_Pin, LOW); 245 | 246 | return val; 247 | } 248 | -------------------------------------------------------------------------------- /_P019_PCF8574.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 019: PCF8574 ############################################## 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_019 6 | #define PLUGIN_ID_019 19 7 | #define PLUGIN_NAME_019 "Switch input - PCF8574" 8 | #define PLUGIN_VALUENAME1_019 "Switch" 9 | 10 | boolean Plugin_019(byte function, struct EventStruct *event, String& string) 11 | { 12 | boolean success = false; 13 | static byte switchstate[TASKS_MAX]; 14 | 15 | switch (function) 16 | { 17 | 18 | case PLUGIN_DEVICE_ADD: 19 | { 20 | Device[++deviceCount].Number = PLUGIN_ID_019; 21 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 22 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 23 | Device[deviceCount].Ports = 8; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = false; 27 | Device[deviceCount].ValueCount = 1; 28 | Device[deviceCount].SendDataOption = true; 29 | Device[deviceCount].TimerOption = true; 30 | Device[deviceCount].TimerOptional = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_019); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_019)); 44 | break; 45 | } 46 | 47 | case PLUGIN_WEBFORM_LOAD: 48 | { 49 | string += F("Send Boot state:"); 50 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 51 | string += F(""); 52 | else 53 | string += F(""); 54 | 55 | success = true; 56 | break; 57 | } 58 | 59 | case PLUGIN_WEBFORM_SAVE: 60 | { 61 | 62 | String plugin1 = WebServer.arg("plugin_019_boot"); 63 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = (plugin1 == "on"); 64 | 65 | success = true; 66 | break; 67 | } 68 | 69 | case PLUGIN_INIT: 70 | { 71 | // read and store current state to prevent switching at boot time 72 | switchstate[event->TaskIndex] = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 73 | 74 | // if boot state must be send, inverse default state 75 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][0]) 76 | switchstate[event->TaskIndex] = !switchstate[event->TaskIndex]; 77 | 78 | success = true; 79 | break; 80 | } 81 | 82 | case PLUGIN_TEN_PER_SECOND: 83 | { 84 | int state = Plugin_019_Read(Settings.TaskDevicePort[event->TaskIndex]); 85 | if (state != -1) 86 | { 87 | if (state != switchstate[event->TaskIndex]) 88 | { 89 | String log = F("PCF : State "); 90 | log += state; 91 | addLog(LOG_LEVEL_INFO, log); 92 | switchstate[event->TaskIndex] = state; 93 | UserVar[event->BaseVarIndex] = state; 94 | event->sensorType = SENSOR_TYPE_SWITCH; 95 | sendData(event); 96 | } 97 | } 98 | success = true; 99 | break; 100 | } 101 | 102 | case PLUGIN_READ: 103 | { 104 | // We do not actually read the pin state as this is already done 10x/second 105 | // Instead we just send the last known state stored in Uservar 106 | String log = F("PCF : State "); 107 | log += UserVar[event->BaseVarIndex]; 108 | addLog(LOG_LEVEL_INFO, log); 109 | success = true; 110 | break; 111 | } 112 | 113 | case PLUGIN_WRITE: 114 | { 115 | String log = ""; 116 | String command = parseString(string, 1); 117 | 118 | if (command == F("pcfgpio")) 119 | { 120 | success = true; 121 | Plugin_019_Write(event->Par1, event->Par2); 122 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 123 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2); 124 | addLog(LOG_LEVEL_INFO, log); 125 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 126 | } 127 | 128 | if (command == F("pcfpulse")) 129 | { 130 | success = true; 131 | Plugin_019_Write(event->Par1, event->Par2); 132 | delay(event->Par3); 133 | Plugin_019_Write(event->Par1, !event->Par2); 134 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 135 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS")); 136 | addLog(LOG_LEVEL_INFO, log); 137 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 138 | } 139 | 140 | if (command == F("pcflongpulse")) 141 | { 142 | success = true; 143 | Plugin_019_Write(event->Par1, event->Par2); 144 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 145 | setSystemTimer(event->Par3 * 1000, PLUGIN_ID_019, event->Par1, !event->Par2, 0); 146 | log = String(F("PCF : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S")); 147 | addLog(LOG_LEVEL_INFO, log); 148 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par1, log, 0)); 149 | } 150 | 151 | if (command == F("status")) 152 | { 153 | if (parseString(string, 2) == F("pcf")) 154 | { 155 | success = true; 156 | String status = ""; 157 | if (hasPinState(PLUGIN_ID_019, event->Par2)) // has been set as output 158 | status = getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par2, dummyString, 0); 159 | else 160 | { 161 | int state = Plugin_019_Read(event->Par2); // report as input 162 | if (state != -1) 163 | status = getPinStateJSON(NO_SEARCH_PIN_STATE, PLUGIN_ID_019, event->Par2, dummyString, state); 164 | } 165 | SendStatus(event->Source, status); 166 | } 167 | } 168 | 169 | break; 170 | } 171 | 172 | case PLUGIN_TIMER_IN: 173 | { 174 | Plugin_019_Write(event->Par1, event->Par2); 175 | setPinState(PLUGIN_ID_019, event->Par1, PIN_MODE_OUTPUT, event->Par2); 176 | break; 177 | } 178 | } 179 | return success; 180 | } 181 | 182 | 183 | //******************************************************************************** 184 | // PCF8574 read 185 | //******************************************************************************** 186 | int Plugin_019_Read(byte Par1) 187 | { 188 | int8_t state = -1; 189 | byte unit = (Par1 - 1) / 8; 190 | byte port = Par1 - (unit * 8); 191 | uint8_t address = 0x20 + unit; 192 | if (unit > 7) address += 0x10; 193 | 194 | // get the current pin status 195 | Wire.requestFrom(address, (uint8_t)0x1); 196 | if (Wire.available()) 197 | { 198 | state = ((Wire.read() & _BV(port - 1)) >> (port - 1)); 199 | } 200 | return state; 201 | } 202 | 203 | 204 | //******************************************************************************** 205 | // PCF8574 write 206 | //******************************************************************************** 207 | boolean Plugin_019_Write(byte Par1, byte Par2) 208 | { 209 | boolean success = false; 210 | byte portvalue = 0; 211 | byte unit = (Par1 - 1) / 8; 212 | byte port = Par1 - (unit * 8); 213 | uint8_t address = 0x20 + unit; 214 | if (unit > 7) address += 0x10; 215 | 216 | // get the current pin status 217 | Wire.requestFrom(address, (uint8_t)0x1); 218 | if (Wire.available()) 219 | { 220 | portvalue = Wire.read(); 221 | if (Par2 == 1) 222 | portvalue |= (1 << (port - 1)); 223 | else 224 | portvalue &= ~(1 << (port - 1)); 225 | 226 | // write back new data 227 | Wire.beginTransmission(address); 228 | Wire.write(portvalue); 229 | Wire.endTransmission(); 230 | success = true; 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /_P011_PME.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 011: Pro Mini Extender #################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_011 6 | #define PLUGIN_ID_011 11 7 | #define PLUGIN_NAME_011 "ProMini Extender" 8 | #define PLUGIN_VALUENAME1_011 "Value" 9 | 10 | #define PLUGIN_011_I2C_ADDRESS 0x7f 11 | 12 | boolean Plugin_011(byte function, struct EventStruct *event, String& string) 13 | { 14 | boolean success = false; 15 | 16 | switch (function) 17 | { 18 | 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_011; 22 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 23 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 24 | Device[deviceCount].PullUpOption = false; 25 | Device[deviceCount].InverseLogicOption = false; 26 | Device[deviceCount].FormulaOption = true; 27 | Device[deviceCount].Ports = 14; 28 | Device[deviceCount].ValueCount = 1; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | break; 32 | } 33 | 34 | case PLUGIN_GET_DEVICENAME: 35 | { 36 | string = F(PLUGIN_NAME_011); 37 | break; 38 | } 39 | 40 | case PLUGIN_GET_DEVICEVALUENAMES: 41 | { 42 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_011)); 43 | break; 44 | } 45 | 46 | case PLUGIN_WEBFORM_LOAD: 47 | { 48 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 49 | String options[2]; 50 | options[0] = F("Digital"); 51 | options[1] = F("Analog"); 52 | int optionValues[2]; 53 | optionValues[0] = 0; 54 | optionValues[1] = 1; 55 | string += F("Port Type:"); 68 | 69 | success = true; 70 | break; 71 | } 72 | 73 | case PLUGIN_WEBFORM_SAVE: 74 | { 75 | String plugin1 = WebServer.arg("plugin_011"); 76 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 77 | success = true; 78 | break; 79 | } 80 | 81 | case PLUGIN_READ: 82 | { 83 | UserVar[event->BaseVarIndex] = Plugin_011_Read(Settings.TaskDevicePluginConfig[event->TaskIndex][0], Settings.TaskDevicePort[event->TaskIndex]); 84 | String log = F("PME : PortValue: "); 85 | log += UserVar[event->BaseVarIndex]; 86 | addLog(LOG_LEVEL_INFO, log); 87 | success = true; 88 | break; 89 | } 90 | 91 | case PLUGIN_WRITE: 92 | { 93 | String log = ""; 94 | String command = parseString(string, 1); 95 | 96 | if (command == F("extgpio")) 97 | { 98 | success = true; 99 | Plugin_011_Write(event->Par1, event->Par2); 100 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 101 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Set to ")) + String(event->Par2); 102 | addLog(LOG_LEVEL_INFO, log); 103 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 104 | } 105 | 106 | if (command == F("extpwm")) 107 | { 108 | success = true; 109 | uint8_t address = PLUGIN_011_I2C_ADDRESS; 110 | Wire.beginTransmission(address); 111 | Wire.write(3); 112 | Wire.write(event->Par1); 113 | Wire.write(event->Par2 & 0xff); 114 | Wire.write((event->Par2 >> 8)); 115 | Wire.endTransmission(); 116 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_PWM, event->Par2); 117 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Set PWM to ")) + String(event->Par2); 118 | addLog(LOG_LEVEL_INFO, log); 119 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 120 | } 121 | 122 | if (command == F("extpulse")) 123 | { 124 | success = true; 125 | if (event->Par1 >= 0 && event->Par1 <= 13) 126 | { 127 | Plugin_011_Write(event->Par1, event->Par2); 128 | delay(event->Par3); 129 | Plugin_011_Write(event->Par1, !event->Par2); 130 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 131 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Pulsed for ")) + String(event->Par3) + String(F(" mS")); 132 | addLog(LOG_LEVEL_INFO, log); 133 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 134 | } 135 | } 136 | 137 | if (command == F("extlongpulse")) 138 | { 139 | success = true; 140 | if (event->Par1 >= 0 && event->Par1 <= 13) 141 | { 142 | Plugin_011_Write(event->Par1, event->Par2); 143 | setSystemTimer(event->Par3 * 1000, PLUGIN_ID_011, event->Par1, !event->Par2, 0); 144 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 145 | log = String(F("PME : GPIO ")) + String(event->Par1) + String(F(" Pulse set for ")) + String(event->Par3) + String(F(" S")); 146 | addLog(LOG_LEVEL_INFO, log); 147 | SendStatus(event->Source, getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par1, log, 0)); 148 | } 149 | } 150 | 151 | if (command == F("status")) 152 | { 153 | if (parseString(string, 2) == F("ext")) 154 | { 155 | success = true; 156 | String status = ""; 157 | if (hasPinState(PLUGIN_ID_011, event->Par2)) // has been set as output 158 | status = getPinStateJSON(SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par2, dummyString, 0); 159 | else 160 | { 161 | byte port = event->Par2; // port 0-13 is digital, ports 20-27 are mapped to A0-A7 162 | byte type = 0; // digital 163 | if (port > 13) 164 | { 165 | type = 1; 166 | port -= 20; 167 | } 168 | int state = Plugin_011_Read(type, port); // report as input (todo: analog reading) 169 | if (state != -1) 170 | status = getPinStateJSON(NO_SEARCH_PIN_STATE, PLUGIN_ID_011, event->Par2, dummyString, state); 171 | } 172 | SendStatus(event->Source, status); 173 | } 174 | } 175 | 176 | break; 177 | } 178 | 179 | case PLUGIN_TIMER_IN: 180 | { 181 | Plugin_011_Write(event->Par1, event->Par2); 182 | setPinState(PLUGIN_ID_011, event->Par1, PIN_MODE_OUTPUT, event->Par2); 183 | break; 184 | } 185 | } 186 | return success; 187 | } 188 | 189 | 190 | //******************************************************************************** 191 | // PME read 192 | //******************************************************************************** 193 | int Plugin_011_Read(byte Par1, byte Par2) 194 | { 195 | int value = -1; 196 | uint8_t address = PLUGIN_011_I2C_ADDRESS; 197 | Wire.beginTransmission(address); 198 | if (Par1 == 0) 199 | Wire.write(2); // Digital Read 200 | else 201 | Wire.write(4); // Analog Read 202 | Wire.write(Par2); 203 | Wire.write(0); 204 | Wire.write(0); 205 | Wire.endTransmission(); 206 | delay(1); // remote unit needs some time for conversion... 207 | Wire.requestFrom(address, (uint8_t)0x4); 208 | byte buffer[4]; 209 | if (Wire.available() == 4) 210 | { 211 | for (byte x = 0; x < 4; x++) 212 | buffer[x] = Wire.read(); 213 | value = buffer[0] + 256 * buffer[1]; 214 | } 215 | return value; 216 | } 217 | 218 | 219 | //******************************************************************************** 220 | // PME write 221 | //******************************************************************************** 222 | boolean Plugin_011_Write(byte Par1, byte Par2) 223 | { 224 | uint8_t address = 0x7f; 225 | Wire.beginTransmission(address); 226 | Wire.write(1); 227 | Wire.write(Par1); 228 | Wire.write(Par2 & 0xff); 229 | Wire.write((Par2 >> 8)); 230 | Wire.endTransmission(); 231 | } 232 | 233 | -------------------------------------------------------------------------------- /_C001.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 001: Domoticz HTTP ###################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_001 6 | #define CPLUGIN_ID_001 1 7 | #define CPLUGIN_NAME_001 "Domoticz HTTP" 8 | 9 | boolean CPlugin_001(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_001; 18 | Protocol[protocolCount].usesMQTT = false; 19 | Protocol[protocolCount].usesAccount = true; 20 | Protocol[protocolCount].usesPassword = true; 21 | Protocol[protocolCount].defaultPort = 8080; 22 | break; 23 | } 24 | 25 | case CPLUGIN_GET_DEVICENAME: 26 | { 27 | string = F(CPLUGIN_NAME_001); 28 | break; 29 | } 30 | 31 | case CPLUGIN_PROTOCOL_SEND: 32 | { 33 | String authHeader = ""; 34 | if ((SecuritySettings.ControllerUser[0] != 0) && (SecuritySettings.ControllerPassword[0] != 0)) 35 | { 36 | base64 encoder; 37 | String auth = SecuritySettings.ControllerUser; 38 | auth += ":"; 39 | auth += SecuritySettings.ControllerPassword; 40 | authHeader = "Authorization: Basic " + encoder.encode(auth) + " \r\n"; 41 | } 42 | 43 | char log[80]; 44 | boolean success = false; 45 | char host[20]; 46 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 47 | 48 | sprintf_P(log, PSTR("%s%s using port %u"), "HTTP : connecting to ", host,Settings.ControllerPort); 49 | addLog(LOG_LEVEL_DEBUG, log); 50 | 51 | // Use WiFiClient class to create TCP connections 52 | WiFiClient client; 53 | if (!client.connect(host, Settings.ControllerPort)) 54 | { 55 | connectionFailures++; 56 | strcpy_P(log, PSTR("HTTP : connection failed")); 57 | addLog(LOG_LEVEL_ERROR, log); 58 | return false; 59 | } 60 | statusLED(true); 61 | if (connectionFailures) 62 | connectionFailures--; 63 | 64 | // We now create a URI for the request 65 | String url = F("/json.htm?type=command¶m=udevice&idx="); 66 | url += event->idx; 67 | 68 | switch (event->sensorType) 69 | { 70 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 71 | url += F("&svalue="); 72 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 73 | break; 74 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 75 | url += F("&svalue="); 76 | url += (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 77 | break; 78 | case SENSOR_TYPE_DUAL: // any sensor that uses two simple values 79 | url += F("&svalue="); 80 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 81 | url += ";"; 82 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 83 | break; 84 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 85 | url += F("&svalue="); 86 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 87 | url += ";"; 88 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 89 | url += ";0"; 90 | break; 91 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 92 | url += F("&svalue="); 93 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 94 | url += ";0;0;"; 95 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 96 | url += ";0"; 97 | break; 98 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 99 | url += F("&svalue="); 100 | url += toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 101 | url += ";"; 102 | url += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 103 | url += ";0;"; 104 | url += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 105 | url += ";0"; 106 | break; 107 | case SENSOR_TYPE_SWITCH: 108 | url = F("/json.htm?type=command¶m=switchlight&idx="); 109 | url += event->idx; 110 | url += F("&switchcmd="); 111 | if (UserVar[event->BaseVarIndex] == 0) 112 | url += "Off"; 113 | else 114 | url += "On"; 115 | break; 116 | case SENSOR_TYPE_DIMMER: 117 | url = F("/json.htm?type=command¶m=switchlight&idx="); 118 | url += event->idx; 119 | url += F("&switchcmd="); 120 | if (UserVar[event->BaseVarIndex] == 0) 121 | url += "Off"; 122 | else 123 | { 124 | url += F("Set%20Level&level="); 125 | url += UserVar[event->BaseVarIndex]; 126 | } 127 | break; 128 | } 129 | 130 | url.toCharArray(log, 80); 131 | addLog(LOG_LEVEL_DEBUG_MORE, log); 132 | 133 | // This will send the request to the server 134 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 135 | "Host: " + host + "\r\n" + authHeader + 136 | "Connection: close\r\n\r\n"); 137 | 138 | unsigned long timer = millis() + 200; 139 | while (!client.available() && millis() < timer) 140 | delay(1); 141 | 142 | // Read all the lines of the reply from server and print them to Serial 143 | while (client.available()) { 144 | String line = client.readStringUntil('\n'); 145 | line.toCharArray(log, 80); 146 | addLog(LOG_LEVEL_DEBUG_MORE, log); 147 | if (line.substring(0, 15) == "HTTP/1.1 200 OK") 148 | { 149 | strcpy_P(log, PSTR("HTTP : Success")); 150 | addLog(LOG_LEVEL_DEBUG, log); 151 | success = true; 152 | } 153 | delay(1); 154 | } 155 | strcpy_P(log, PSTR("HTTP : closing connection")); 156 | addLog(LOG_LEVEL_DEBUG, log); 157 | 158 | client.flush(); 159 | client.stop(); 160 | 161 | break; 162 | } 163 | 164 | } 165 | return success; 166 | } 167 | 168 | boolean Domoticz_getData(int idx, float *data) 169 | { 170 | boolean success = false; 171 | char host[20]; 172 | sprintf_P(host, PSTR("%u.%u.%u.%u"), Settings.Controller_IP[0], Settings.Controller_IP[1], Settings.Controller_IP[2], Settings.Controller_IP[3]); 173 | 174 | // Use WiFiClient class to create TCP connections 175 | WiFiClient client; 176 | if (!client.connect(host, Settings.ControllerPort)) 177 | { 178 | connectionFailures++; 179 | return false; 180 | } 181 | if (connectionFailures) 182 | connectionFailures--; 183 | 184 | // We now create a URI for the request 185 | String url = F("/json.htm?type=devices&rid="); 186 | url += idx; 187 | 188 | // This will send the request to the server 189 | client.print(String("GET ") + url + " HTTP/1.1\r\n" + 190 | "Host: " + host + "\r\n" + 191 | "Connection: close\r\n\r\n"); 192 | 193 | unsigned long timer = millis() + 200; 194 | while (!client.available() && millis() < timer) 195 | delay(1); 196 | 197 | // Read all the lines of the reply from server and print them to Serial 198 | 199 | while (client.available()) { 200 | String line = client.readStringUntil('\n'); 201 | if (line.substring(10, 14) == "Data") 202 | { 203 | String strValue = line.substring(19); 204 | byte pos = strValue.indexOf(' '); 205 | strValue = strValue.substring(0, pos); 206 | strValue.trim(); 207 | float value = strValue.toFloat(); 208 | *data = value; 209 | success = true; 210 | } 211 | } 212 | return success; 213 | } 214 | 215 | 216 | -------------------------------------------------------------------------------- /_P012_LCD.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 012: LCD ################################################## 3 | //####################################################################################################### 4 | 5 | // Sample templates 6 | // Temp: [DHT11#Temperature] Hum:[DHT11#humidity] 7 | // DS Temp:[Dallas1#Temperature#R] 8 | // Lux:[Lux#Lux#R] 9 | // Baro:[Baro#Pressure#R] 10 | 11 | LiquidCrystal_I2C *lcd; 12 | 13 | #define PLUGIN_012 14 | #define PLUGIN_ID_012 12 15 | #define PLUGIN_NAME_012 "Display - LCD2004" 16 | #define PLUGIN_VALUENAME1_012 "LCD" 17 | 18 | boolean Plugin_012(byte function, struct EventStruct *event, String& string) 19 | { 20 | boolean success = false; 21 | static byte displayTimer = 0; 22 | 23 | switch (function) 24 | { 25 | 26 | case PLUGIN_DEVICE_ADD: 27 | { 28 | Device[++deviceCount].Number = PLUGIN_ID_012; 29 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 30 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 31 | Device[deviceCount].Ports = 0; 32 | Device[deviceCount].PullUpOption = false; 33 | Device[deviceCount].InverseLogicOption = false; 34 | Device[deviceCount].FormulaOption = false; 35 | Device[deviceCount].ValueCount = 0; 36 | Device[deviceCount].SendDataOption = false; 37 | Device[deviceCount].TimerOption = true; 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICENAME: 42 | { 43 | string = F(PLUGIN_NAME_012); 44 | break; 45 | } 46 | 47 | case PLUGIN_GET_DEVICEVALUENAMES: 48 | { 49 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_012)); 50 | break; 51 | } 52 | 53 | case PLUGIN_WEBFORM_LOAD: 54 | { 55 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 56 | int optionValues[16]; 57 | for (byte x = 0; x < 17; x++) 58 | if (x < 8) 59 | optionValues[x] = 0x20 + x; 60 | else 61 | optionValues[x] = 0x30 + x; 62 | 63 | string += F("I2C Address:"); 76 | 77 | byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 78 | String options2[2]; 79 | options2[0] = F("2 x 16"); 80 | options2[1] = F("4 x 20"); 81 | int optionValues2[2]; 82 | optionValues2[0] = 1; 83 | optionValues2[1] = 2; 84 | string += F("Display Size:"); 97 | 98 | char deviceTemplate[4][80]; 99 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 100 | for (byte varNr = 0; varNr < 4; varNr++) 101 | { 102 | string += F("Line "); 103 | string += varNr + 1; 104 | string += F(":"); 109 | } 110 | 111 | string += F("Display button:"); 112 | addPinSelect(false, string, "taskdevicepin3", Settings.TaskDevicePin3[event->TaskIndex]); 113 | 114 | char tmpString[128]; 115 | 116 | sprintf_P(tmpString, PSTR("Display Timeout:"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]); 117 | string += tmpString; 118 | 119 | success = true; 120 | break; 121 | } 122 | 123 | case PLUGIN_WEBFORM_SAVE: 124 | { 125 | String plugin1 = WebServer.arg("plugin_012_adr"); 126 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 127 | String plugin2 = WebServer.arg("plugin_012_size"); 128 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 129 | String plugin3 = WebServer.arg("plugin_12_timer"); 130 | Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); 131 | 132 | char deviceTemplate[4][80]; 133 | for (byte varNr = 0; varNr < 4; varNr++) 134 | { 135 | char argc[25]; 136 | String arg = F("Plugin_012_template"); 137 | arg += varNr + 1; 138 | arg.toCharArray(argc, 25); 139 | String tmpString = WebServer.arg(argc); 140 | strncpy(deviceTemplate[varNr], tmpString.c_str(), sizeof(deviceTemplate[varNr])); 141 | } 142 | 143 | Settings.TaskDeviceID[event->TaskIndex] = 1; // temp fix, needs a dummy value 144 | 145 | SaveCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 146 | success = true; 147 | break; 148 | } 149 | 150 | case PLUGIN_INIT: 151 | { 152 | if (!lcd) 153 | { 154 | byte row = 2; 155 | byte col = 16; 156 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 157 | { 158 | row = 4; 159 | col = 20; 160 | } 161 | lcd = new LiquidCrystal_I2C(Settings.TaskDevicePluginConfig[event->TaskIndex][0], col, row); 162 | } 163 | // Setup LCD display 164 | lcd->init(); // initialize the lcd 165 | lcd->backlight(); 166 | lcd->print("ESP Easy"); 167 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 168 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 169 | pinMode(Settings.TaskDevicePin3[event->TaskIndex], INPUT_PULLUP); 170 | success = true; 171 | break; 172 | } 173 | 174 | case PLUGIN_TEN_PER_SECOND: 175 | { 176 | if (Settings.TaskDevicePin3[event->TaskIndex] != -1) 177 | { 178 | if (!digitalRead(Settings.TaskDevicePin3[event->TaskIndex])) 179 | { 180 | lcd->backlight(); 181 | displayTimer = Settings.TaskDevicePluginConfig[event->TaskIndex][2]; 182 | } 183 | } 184 | break; 185 | } 186 | 187 | case PLUGIN_ONCE_A_SECOND: 188 | { 189 | if ( displayTimer > 0) 190 | { 191 | displayTimer--; 192 | if (displayTimer == 0) 193 | lcd->noBacklight(); 194 | } 195 | break; 196 | } 197 | 198 | case PLUGIN_READ: 199 | { 200 | char deviceTemplate[4][80]; 201 | LoadCustomTaskSettings(event->TaskIndex, (byte*)&deviceTemplate, sizeof(deviceTemplate)); 202 | 203 | byte row = 2; 204 | byte col = 16; 205 | if (Settings.TaskDevicePluginConfig[event->TaskIndex][1] == 2) 206 | { 207 | row = 4; 208 | col = 20; 209 | } 210 | 211 | for (byte x = 0; x < row; x++) 212 | { 213 | String tmpString = deviceTemplate[x]; 214 | if (tmpString.length()) 215 | { 216 | String newString = parseTemplate(tmpString, col); 217 | lcd->setCursor(0, x); 218 | lcd->print(newString); 219 | } 220 | } 221 | success = false; 222 | break; 223 | } 224 | 225 | case PLUGIN_WRITE: 226 | { 227 | String tmpString = string; 228 | int argIndex = tmpString.indexOf(','); 229 | if (argIndex) 230 | tmpString = tmpString.substring(0, argIndex); 231 | if (tmpString.equalsIgnoreCase(F("LCD"))) 232 | { 233 | success = true; 234 | argIndex = string.lastIndexOf(','); 235 | tmpString = string.substring(argIndex + 1); 236 | lcd->setCursor(event->Par2 - 1, event->Par1 - 1); 237 | lcd->print(tmpString.c_str()); 238 | } 239 | if (tmpString.equalsIgnoreCase(F("LCDCMD"))) 240 | { 241 | success = true; 242 | argIndex = string.lastIndexOf(','); 243 | tmpString = string.substring(argIndex + 1); 244 | if (tmpString.equalsIgnoreCase(F("Off"))) 245 | lcd->noBacklight(); 246 | else if (tmpString.equalsIgnoreCase(F("On"))) 247 | lcd->backlight(); 248 | else if (tmpString.equalsIgnoreCase(F("Clear"))) 249 | lcd->clear(); 250 | } 251 | break; 252 | } 253 | 254 | } 255 | return success; 256 | } 257 | -------------------------------------------------------------------------------- /_C002.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //########################### Controller Plugin 002: Domoticz MQTT ###################################### 3 | //####################################################################################################### 4 | 5 | #define CPLUGIN_002 6 | #define CPLUGIN_ID_002 2 7 | #define CPLUGIN_NAME_002 "Domoticz MQTT" 8 | 9 | boolean CPlugin_002(byte function, struct EventStruct *event, String& string) 10 | { 11 | boolean success = false; 12 | 13 | switch (function) 14 | { 15 | case CPLUGIN_PROTOCOL_ADD: 16 | { 17 | Protocol[++protocolCount].Number = CPLUGIN_ID_002; 18 | Protocol[protocolCount].usesMQTT = true; 19 | Protocol[protocolCount].usesTemplate = true; 20 | Protocol[protocolCount].usesAccount = true; 21 | Protocol[protocolCount].usesPassword = true; 22 | Protocol[protocolCount].defaultPort = 1883; 23 | break; 24 | } 25 | 26 | case CPLUGIN_GET_DEVICENAME: 27 | { 28 | string = F(CPLUGIN_NAME_002); 29 | break; 30 | } 31 | 32 | case CPLUGIN_PROTOCOL_TEMPLATE: 33 | { 34 | strcpy_P(Settings.MQTTsubscribe, PSTR("domoticz/out")); 35 | strcpy_P(Settings.MQTTpublish, PSTR("domoticz/in")); 36 | break; 37 | } 38 | 39 | case CPLUGIN_PROTOCOL_RECV: 40 | { 41 | char json[512]; 42 | json[0] = 0; 43 | event->String2.toCharArray(json, 512); 44 | 45 | StaticJsonBuffer<512> jsonBuffer; 46 | JsonObject& root = jsonBuffer.parseObject(json); 47 | 48 | if (root.success()) 49 | { 50 | long idx = root["idx"]; 51 | float nvalue = root["nvalue"]; 52 | long nvaluealt = root["nvalue"]; 53 | //const char* name = root["name"]; // Not used 54 | //const char* svalue = root["svalue"]; // Not used 55 | const char* svalue1 = root["svalue1"]; 56 | //const char* svalue2 = root["svalue2"]; // Not used 57 | //const char* svalue3 = root["svalue3"]; // Not used 58 | const char* switchtype = root["switchType"]; // Expect "On/Off" or "dimmer" 59 | if (nvalue == 0) 60 | nvalue = nvaluealt; 61 | if ((int)switchtype == 0) 62 | switchtype = "?"; 63 | 64 | for (byte x = 0; x < TASKS_MAX; x++) 65 | { 66 | if (Settings.TaskDeviceID[x] == idx) 67 | { 68 | if (Settings.TaskDeviceNumber[x] == 1) // temp solution, if input switch, update state 69 | { 70 | String action = F("inputSwitchState,"); 71 | action += x; 72 | action += ","; 73 | action += nvalue; 74 | struct EventStruct TempEvent; 75 | parseCommandString(&TempEvent, action); 76 | PluginCall(PLUGIN_WRITE, &TempEvent, action); 77 | } 78 | if (Settings.TaskDeviceNumber[x] == 29) // temp solution, if plugin 029, set gpio 79 | { 80 | String action = ""; 81 | int baseVar = x * VARS_PER_TASK; 82 | struct EventStruct TempEvent; 83 | if (strcasecmp_P(switchtype, PSTR("dimmer")) == 0) 84 | { 85 | int pwmValue = UserVar[baseVar]; 86 | action = F("pwm,"); 87 | action += Settings.TaskDevicePin1[x]; 88 | action += ","; 89 | switch ((int)nvalue) 90 | { 91 | case 0: 92 | pwmValue = 0; 93 | break; 94 | case 1: 95 | pwmValue = UserVar[baseVar]; 96 | break; 97 | case 2: 98 | pwmValue = 10 * atol(svalue1); 99 | UserVar[baseVar] = pwmValue; 100 | break; 101 | } 102 | action += pwmValue; 103 | } 104 | else 105 | { 106 | UserVar[baseVar] = nvalue; 107 | action = F("gpio,"); 108 | action += Settings.TaskDevicePin1[x]; 109 | action += ","; 110 | action += nvalue; 111 | } 112 | parseCommandString(&TempEvent, action); 113 | PluginCall(PLUGIN_WRITE, &TempEvent, action); 114 | } 115 | } 116 | } 117 | } 118 | break; 119 | } 120 | 121 | case CPLUGIN_PROTOCOL_SEND: 122 | { 123 | StaticJsonBuffer<200> jsonBuffer; 124 | 125 | JsonObject& root = jsonBuffer.createObject(); 126 | 127 | root["idx"] = event->idx; 128 | 129 | String values; 130 | char str[80]; 131 | 132 | switch (event->sensorType) 133 | { 134 | case SENSOR_TYPE_SINGLE: // single value sensor, used for Dallas, BH1750, etc 135 | root["nvalue"] = 0; 136 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 137 | values.toCharArray(str, 80); 138 | root["svalue"] = str; 139 | break; 140 | case SENSOR_TYPE_LONG: // single LONG value, stored in two floats (rfid tags) 141 | root["nvalue"] = 0; 142 | values = (unsigned long)UserVar[event->BaseVarIndex] + ((unsigned long)UserVar[event->BaseVarIndex + 1] << 16); 143 | values.toCharArray(str, 80); 144 | root["svalue"] = str; 145 | break; 146 | case SENSOR_TYPE_DUAL: // any sensor that uses two simple values 147 | root["nvalue"] = 0; 148 | values = toString(UserVar[event->BaseVarIndex ],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 149 | values += ";"; 150 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 151 | values.toCharArray(str, 80); 152 | root["svalue"] = str; 153 | break; 154 | case SENSOR_TYPE_TEMP_HUM: // temp + hum + hum_stat, used for DHT11 155 | root["nvalue"] = 0; 156 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 157 | values += ";"; 158 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 159 | values += ";0"; 160 | values.toCharArray(str, 80); 161 | root["svalue"] = str; 162 | break; 163 | case SENSOR_TYPE_TEMP_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BMP085 164 | root["nvalue"] = 0; 165 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 166 | values += ";0;0;"; 167 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 168 | values += ";0"; 169 | values.toCharArray(str, 80); 170 | root["svalue"] = str; 171 | break; 172 | case SENSOR_TYPE_TEMP_HUM_BARO: // temp + hum + hum_stat + bar + bar_fore, used for BME280 173 | root["nvalue"] = 0; 174 | values = toString(UserVar[event->BaseVarIndex],ExtraTaskSettings.TaskDeviceValueDecimals[0]); 175 | values += ";"; 176 | values += toString(UserVar[event->BaseVarIndex + 1],ExtraTaskSettings.TaskDeviceValueDecimals[1]); 177 | values += ";0;"; 178 | values += toString(UserVar[event->BaseVarIndex + 2],ExtraTaskSettings.TaskDeviceValueDecimals[2]); 179 | values += ";0"; 180 | values.toCharArray(str, 80); 181 | root["svalue"] = str; 182 | break; 183 | case SENSOR_TYPE_SWITCH: 184 | root["command"] = "switchlight"; 185 | if (UserVar[event->BaseVarIndex] == 0) 186 | root["switchcmd"] = "Off"; 187 | else 188 | root["switchcmd"] = "On"; 189 | break; 190 | case SENSOR_TYPE_DIMMER: 191 | root["command"] = "switchlight"; 192 | if (UserVar[event->BaseVarIndex] == 0) 193 | root["switchcmd"] = "Off"; 194 | else 195 | root["Set%20Level"] = UserVar[event->BaseVarIndex]; 196 | break; 197 | } 198 | 199 | char json[256]; 200 | root.printTo(json, sizeof(json)); 201 | String log = F("MQTT : "); 202 | log += json; 203 | addLog(LOG_LEVEL_DEBUG, json); 204 | 205 | String pubname = Settings.MQTTpublish; 206 | pubname.replace("%sysname%", Settings.Name); 207 | pubname.replace("%tskname%", ExtraTaskSettings.TaskDeviceName); 208 | pubname.replace("%id%", String(event->idx)); 209 | 210 | if (!MQTTclient.publish(pubname.c_str(), json, Settings.MQTTRetainFlag)) 211 | { 212 | log = F("MQTT publish failed"); 213 | addLog(LOG_LEVEL_DEBUG, json); 214 | MQTTConnect(); 215 | connectionFailures++; 216 | } 217 | else if (connectionFailures) 218 | connectionFailures--; 219 | break; 220 | } 221 | 222 | } 223 | return success; 224 | } 225 | 226 | -------------------------------------------------------------------------------- /_P003_Pulse.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //#################################### Plugin 003: Pulse ############################################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_003 6 | #define PLUGIN_ID_003 3 7 | #define PLUGIN_NAME_003 "Pulse Counter" 8 | #define PLUGIN_VALUENAME1_003 "Count" 9 | #define PLUGIN_VALUENAME2_003 "Total" 10 | #define PLUGIN_VALUENAME3_003 "Time" 11 | 12 | void Plugin_003_pulse_interrupt1() ICACHE_RAM_ATTR; 13 | void Plugin_003_pulse_interrupt2() ICACHE_RAM_ATTR; 14 | void Plugin_003_pulse_interrupt3() ICACHE_RAM_ATTR; 15 | void Plugin_003_pulse_interrupt4() ICACHE_RAM_ATTR; 16 | void Plugin_003_pulse_interrupt5() ICACHE_RAM_ATTR; 17 | void Plugin_003_pulse_interrupt6() ICACHE_RAM_ATTR; 18 | void Plugin_003_pulse_interrupt7() ICACHE_RAM_ATTR; 19 | void Plugin_003_pulse_interrupt8() ICACHE_RAM_ATTR; 20 | 21 | unsigned long Plugin_003_pulseCounter[TASKS_MAX]; 22 | unsigned long Plugin_003_pulseTotalCounter[TASKS_MAX]; 23 | unsigned long Plugin_003_pulseTime[TASKS_MAX]; 24 | unsigned long Plugin_003_pulseTimePrevious[TASKS_MAX]; 25 | 26 | boolean Plugin_003(byte function, struct EventStruct *event, String& string) 27 | { 28 | boolean success = false; 29 | 30 | switch (function) 31 | { 32 | 33 | case PLUGIN_DEVICE_ADD: 34 | { 35 | Device[++deviceCount].Number = PLUGIN_ID_003; 36 | Device[deviceCount].Type = DEVICE_TYPE_SINGLE; 37 | Device[deviceCount].VType = SENSOR_TYPE_SINGLE; 38 | Device[deviceCount].Ports = 0; 39 | Device[deviceCount].PullUpOption = false; 40 | Device[deviceCount].InverseLogicOption = false; 41 | Device[deviceCount].FormulaOption = true; 42 | Device[deviceCount].ValueCount = 3; 43 | Device[deviceCount].SendDataOption = true; 44 | Device[deviceCount].TimerOption = true; 45 | Device[deviceCount].GlobalSyncOption = true; 46 | break; 47 | } 48 | 49 | case PLUGIN_GET_DEVICENAME: 50 | { 51 | string = F(PLUGIN_NAME_003); 52 | break; 53 | } 54 | 55 | case PLUGIN_GET_DEVICEVALUENAMES: 56 | { 57 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_003)); 58 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_003)); 59 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[2], PSTR(PLUGIN_VALUENAME3_003)); 60 | break; 61 | } 62 | 63 | case PLUGIN_WEBFORM_LOAD: 64 | { 65 | char tmpString[128]; 66 | sprintf_P(tmpString, PSTR("Debounce Time (mSec):"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 67 | string += tmpString; 68 | 69 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 70 | String options[3]; 71 | options[0] = F("Delta"); 72 | options[1] = F("Delta/Total/Time"); 73 | options[2] = F("Total"); 74 | int optionValues[3]; 75 | optionValues[0] = 0; 76 | optionValues[1] = 1; 77 | optionValues[2] = 2; 78 | string += F("Counter Type:"); 91 | 92 | if (choice !=0) 93 | string += F("Total count is not persistent!"); 94 | 95 | success = true; 96 | break; 97 | } 98 | 99 | case PLUGIN_WEBFORM_SAVE: 100 | { 101 | String plugin1 = WebServer.arg("plugin_003"); 102 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 103 | String plugin2 = WebServer.arg("plugin_003_countertype"); 104 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); 105 | success = true; 106 | break; 107 | } 108 | 109 | case PLUGIN_WEBFORM_SHOW_VALUES: 110 | { 111 | string += F("
"); 112 | string += ExtraTaskSettings.TaskDeviceValueNames[0]; 113 | string += F(":
"); 114 | string += Plugin_003_pulseCounter[event->TaskIndex]; 115 | string += F("
"); 116 | string += ExtraTaskSettings.TaskDeviceValueNames[1]; 117 | string += F(":
"); 118 | string += Plugin_003_pulseTotalCounter[event->TaskIndex]; 119 | string += F("
"); 120 | string += ExtraTaskSettings.TaskDeviceValueNames[2]; 121 | string += F(":
"); 122 | string += Plugin_003_pulseTime[event->TaskIndex]; 123 | string += F("
"); 124 | success = true; 125 | break; 126 | } 127 | 128 | case PLUGIN_INIT: 129 | { 130 | String log = F("INIT : Pulse "); 131 | log += Settings.TaskDevicePin1[event->TaskIndex]; 132 | addLog(LOG_LEVEL_INFO,log); 133 | pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP); 134 | Plugin_003_pulseinit(Settings.TaskDevicePin1[event->TaskIndex], event->TaskIndex); 135 | success = true; 136 | break; 137 | } 138 | 139 | case PLUGIN_READ: 140 | { 141 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 142 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 143 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 144 | 145 | switch (Settings.TaskDevicePluginConfig[event->TaskIndex][1]) 146 | { 147 | case 0: 148 | { 149 | event->sensorType = SENSOR_TYPE_SINGLE; 150 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 151 | break; 152 | } 153 | case 1: 154 | { 155 | event->sensorType = SENSOR_TYPE_TRIPLE; 156 | UserVar[event->BaseVarIndex] = Plugin_003_pulseCounter[event->TaskIndex]; 157 | UserVar[event->BaseVarIndex+1] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 158 | UserVar[event->BaseVarIndex+2] = Plugin_003_pulseTime[event->TaskIndex]; 159 | break; 160 | } 161 | case 2: 162 | { 163 | event->sensorType = SENSOR_TYPE_SINGLE; 164 | UserVar[event->BaseVarIndex] = Plugin_003_pulseTotalCounter[event->TaskIndex]; 165 | break; 166 | } 167 | } 168 | Plugin_003_pulseCounter[event->TaskIndex] = 0; 169 | success = true; 170 | break; 171 | } 172 | } 173 | return success; 174 | } 175 | 176 | 177 | /*********************************************************************************************\ 178 | * Check Pulse Counters (called from irq handler) 179 | \*********************************************************************************************/ 180 | void Plugin_003_pulsecheck(byte Index) 181 | { 182 | unsigned long PulseTime=millis() - Plugin_003_pulseTimePrevious[Index]; 183 | if(PulseTime > Settings.TaskDevicePluginConfig[Index][0]) // check with debounce time for this task 184 | { 185 | Plugin_003_pulseCounter[Index]++; 186 | Plugin_003_pulseTotalCounter[Index]++; 187 | Plugin_003_pulseTime[Index] = PulseTime; 188 | Plugin_003_pulseTimePrevious[Index]=millis(); 189 | } 190 | } 191 | 192 | 193 | /*********************************************************************************************\ 194 | * Pulse Counter IRQ handlers 195 | \*********************************************************************************************/ 196 | void Plugin_003_pulse_interrupt1() 197 | { 198 | Plugin_003_pulsecheck(0); 199 | } 200 | void Plugin_003_pulse_interrupt2() 201 | { 202 | Plugin_003_pulsecheck(1); 203 | } 204 | void Plugin_003_pulse_interrupt3() 205 | { 206 | Plugin_003_pulsecheck(2); 207 | } 208 | void Plugin_003_pulse_interrupt4() 209 | { 210 | Plugin_003_pulsecheck(3); 211 | } 212 | void Plugin_003_pulse_interrupt5() 213 | { 214 | Plugin_003_pulsecheck(4); 215 | } 216 | void Plugin_003_pulse_interrupt6() 217 | { 218 | Plugin_003_pulsecheck(5); 219 | } 220 | void Plugin_003_pulse_interrupt7() 221 | { 222 | Plugin_003_pulsecheck(6); 223 | } 224 | void Plugin_003_pulse_interrupt8() 225 | { 226 | Plugin_003_pulsecheck(7); 227 | } 228 | 229 | 230 | /*********************************************************************************************\ 231 | * Init Pulse Counters 232 | \*********************************************************************************************/ 233 | void Plugin_003_pulseinit(byte Par1, byte Index) 234 | { 235 | // Init IO pins 236 | String log = F("PULSE: Init"); 237 | addLog(LOG_LEVEL_INFO,log); 238 | 239 | switch (Index) 240 | { 241 | case 0: 242 | attachInterrupt(Par1, Plugin_003_pulse_interrupt1, FALLING); 243 | break; 244 | case 1: 245 | attachInterrupt(Par1, Plugin_003_pulse_interrupt2, FALLING); 246 | break; 247 | case 2: 248 | attachInterrupt(Par1, Plugin_003_pulse_interrupt3, FALLING); 249 | break; 250 | case 3: 251 | attachInterrupt(Par1, Plugin_003_pulse_interrupt4, FALLING); 252 | break; 253 | case 4: 254 | attachInterrupt(Par1, Plugin_003_pulse_interrupt5, FALLING); 255 | break; 256 | case 5: 257 | attachInterrupt(Par1, Plugin_003_pulse_interrupt6, FALLING); 258 | break; 259 | case 6: 260 | attachInterrupt(Par1, Plugin_003_pulse_interrupt7, FALLING); 261 | break; 262 | case 7: 263 | attachInterrupt(Par1, Plugin_003_pulse_interrupt8, FALLING); 264 | break; 265 | } 266 | } 267 | -------------------------------------------------------------------------------- /_P032_MS5611.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //################ Plugin 032 MS5611 (GY-63) I2C Temp/Barometric Pressure Sensor ####################### 3 | //####################################################################################################### 4 | // This sketch is based on https://github.com/Schm1tz1/arduino-ms5xxx 5 | 6 | #define PLUGIN_032 7 | #define PLUGIN_ID_032 32 8 | #define PLUGIN_NAME_032 "Temperature & Pressure - MS5611 (GY-63)" 9 | #define PLUGIN_VALUENAME1_032 "Temperature" 10 | #define PLUGIN_VALUENAME2_032 "Pressure" 11 | 12 | enum 13 | { 14 | MS5xxx_CMD_RESET = 0x1E, // perform reset 15 | MS5xxx_CMD_ADC_READ = 0x00, // initiate read sequence 16 | MS5xxx_CMD_ADC_CONV = 0x40, // start conversion 17 | MS5xxx_CMD_ADC_D1 = 0x00, // read ADC 1 18 | MS5xxx_CMD_ADC_D2 = 0x10, // read ADC 2 19 | MS5xxx_CMD_ADC_256 = 0x00, // set ADC oversampling ratio to 256 20 | MS5xxx_CMD_ADC_512 = 0x02, // set ADC oversampling ratio to 512 21 | MS5xxx_CMD_ADC_1024 = 0x04, // set ADC oversampling ratio to 1024 22 | MS5xxx_CMD_ADC_2048 = 0x06, // set ADC oversampling ratio to 2048 23 | MS5xxx_CMD_ADC_4096 = 0x08, // set ADC oversampling ratio to 4096 24 | MS5xxx_CMD_PROM_RD = 0xA0 // initiate readout of PROM registers 25 | }; 26 | 27 | 28 | 29 | uint8_t ms5611_i2caddr; 30 | unsigned int ms5611_prom[8]; 31 | double ms5611_pressure; 32 | double ms5611_temperature; 33 | 34 | boolean Plugin_032_init = false; 35 | 36 | boolean Plugin_032(byte function, struct EventStruct *event, String& string) 37 | { 38 | boolean success = false; 39 | 40 | switch (function) 41 | { 42 | case PLUGIN_DEVICE_ADD: 43 | { 44 | Device[++deviceCount].Number = PLUGIN_ID_032; 45 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 46 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_BARO; 47 | Device[deviceCount].Ports = 0; 48 | Device[deviceCount].PullUpOption = false; 49 | Device[deviceCount].InverseLogicOption = false; 50 | Device[deviceCount].FormulaOption = true; 51 | Device[deviceCount].ValueCount = 2; 52 | Device[deviceCount].SendDataOption = true; 53 | Device[deviceCount].TimerOption = true; 54 | Device[deviceCount].GlobalSyncOption = true; 55 | break; 56 | } 57 | 58 | case PLUGIN_GET_DEVICENAME: 59 | { 60 | string = F(PLUGIN_NAME_032); 61 | break; 62 | } 63 | 64 | case PLUGIN_GET_DEVICEVALUENAMES: 65 | { 66 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_032)); 67 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_032)); 68 | break; 69 | } 70 | case PLUGIN_WEBFORM_LOAD: 71 | { 72 | byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; 73 | String options[2]; 74 | options[0] = F("0x77 - default I2C address"); 75 | options[1] = F("0x76 - alternate I2C address"); 76 | int optionValues[2]; 77 | optionValues[0] = 0x77; 78 | optionValues[1] = 0x76; 79 | string += F("I2C Address:"); 92 | string += F("Altitude [m]:"); 96 | 97 | success = true; 98 | break; 99 | } 100 | 101 | case PLUGIN_WEBFORM_SAVE: 102 | { 103 | String plugin1 = WebServer.arg("plugin_032_ms5611_i2c"); 104 | Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); 105 | String elev = WebServer.arg("plugin_032_ms5611_elev"); 106 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt(); 107 | success = true; 108 | break; 109 | } 110 | 111 | case PLUGIN_READ: 112 | { 113 | if (!Plugin_032_init) 114 | { 115 | Plugin_032_init = Plugin_032_begin(Settings.TaskDevicePluginConfig[event->TaskIndex][0]); 116 | } 117 | 118 | if (Plugin_032_init) { 119 | Plugin_032_read_prom(); 120 | Plugin_032_readout(); 121 | 122 | UserVar[event->BaseVarIndex] = ms5611_temperature / 100; 123 | int elev = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 124 | if (elev) 125 | { 126 | UserVar[event->BaseVarIndex + 1] = Plugin_032_pressureElevation(ms5611_pressure, elev); 127 | } else { 128 | UserVar[event->BaseVarIndex + 1] = ms5611_pressure; 129 | } 130 | 131 | String log = F("MS5611 : Temperature: "); 132 | log += UserVar[event->BaseVarIndex]; 133 | addLog(LOG_LEVEL_INFO, log); 134 | log = F("MS5611 : Barometric Pressure: "); 135 | log += UserVar[event->BaseVarIndex + 1]; 136 | addLog(LOG_LEVEL_INFO, log); 137 | success = true; 138 | } 139 | break; 140 | } 141 | 142 | } 143 | return success; 144 | } 145 | 146 | //**************************************************************************/ 147 | // Initialize MS5611 148 | //**************************************************************************/ 149 | bool Plugin_032_begin(uint8_t a) { 150 | ms5611_i2caddr = a; 151 | 152 | Wire.beginTransmission((uint8_t)ms5611_i2caddr); 153 | uint8_t ret=Wire.endTransmission(true); 154 | return ret==0; 155 | } 156 | 157 | //**************************************************************************/ 158 | // Sends a command over I2C 159 | //**************************************************************************/ 160 | byte Plugin_032_send_cmd(byte aCMD) 161 | { 162 | Wire.beginTransmission((uint8_t)ms5611_i2caddr); 163 | Wire.write(aCMD); 164 | uint8_t ret=Wire.endTransmission(true); 165 | return ret; 166 | } 167 | 168 | //**************************************************************************/ 169 | // Reads the PROM of MS5611 170 | // There are in total 8 addresses resulting in a total memory of 128 bit. 171 | // Address 0 contains factory data and the setup, addresses 1-6 calibration 172 | // coefficients and address 7 contains the serial code and CRC. 173 | // The command sequence is 8 bits long with a 16 bit result which is 174 | // clocked with the MSB first. 175 | //**************************************************************************/ 176 | void Plugin_032_read_prom() { 177 | Plugin_032_send_cmd(MS5xxx_CMD_RESET); 178 | delay(3); 179 | 180 | for(uint8_t i=0;i<8;i++) 181 | { 182 | ms5611_prom[i]=0x0000; 183 | Plugin_032_send_cmd(MS5xxx_CMD_PROM_RD+2*i); 184 | Wire.requestFrom((uint8_t)ms5611_i2caddr, (uint8_t)2); 185 | 186 | unsigned int c = Wire.read(); 187 | ms5611_prom[i] = (c << 8); 188 | c = Wire.read(); 189 | ms5611_prom[i] += c; 190 | Wire.endTransmission(true); 191 | } 192 | } 193 | 194 | //**************************************************************************/ 195 | // Read analog/digital converter 196 | //**************************************************************************/ 197 | unsigned long Plugin_032_read_adc(unsigned char aCMD) 198 | { 199 | unsigned long value=0; 200 | unsigned long c=0; 201 | 202 | Plugin_032_send_cmd(MS5xxx_CMD_ADC_CONV+aCMD); // start DAQ and conversion of ADC data 203 | switch (aCMD & 0x0f) 204 | { 205 | case MS5xxx_CMD_ADC_256 : delayMicroseconds(900); 206 | break; 207 | case MS5xxx_CMD_ADC_512 : delay(3); 208 | break; 209 | case MS5xxx_CMD_ADC_1024: delay(4); 210 | break; 211 | case MS5xxx_CMD_ADC_2048: delay(6); 212 | break; 213 | case MS5xxx_CMD_ADC_4096: delay(10); 214 | break; 215 | } 216 | Plugin_032_send_cmd(MS5xxx_CMD_ADC_READ); // read out values 217 | Wire.requestFrom((uint8_t)ms5611_i2caddr, (uint8_t)3); 218 | c = Wire.read(); 219 | value = (c<<16); 220 | c = Wire.read(); 221 | value += (c<<8); 222 | c = Wire.read(); 223 | value += c; 224 | Wire.endTransmission(true); 225 | 226 | return value; 227 | } 228 | 229 | 230 | //**************************************************************************/ 231 | // Readout 232 | //**************************************************************************/ 233 | void Plugin_032_readout() { 234 | 235 | unsigned long D1=0, D2=0; 236 | 237 | double dT; 238 | double OFF; 239 | double SENS; 240 | 241 | D2=Plugin_032_read_adc(MS5xxx_CMD_ADC_D2+MS5xxx_CMD_ADC_4096); 242 | D1=Plugin_032_read_adc(MS5xxx_CMD_ADC_D1+MS5xxx_CMD_ADC_4096); 243 | 244 | // calculate 1st order pressure and temperature (MS5611 1st order algorithm) 245 | dT=D2-ms5611_prom[5]*pow(2,8); 246 | OFF=ms5611_prom[2]*pow(2,16)+dT*ms5611_prom[4]/pow(2,7); 247 | SENS=ms5611_prom[1]*pow(2,15)+dT*ms5611_prom[3]/pow(2,8); 248 | ms5611_temperature=(2000+(dT*ms5611_prom[6])/pow(2,23)); 249 | ms5611_pressure=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15)); 250 | 251 | // perform higher order corrections 252 | double T2=0., OFF2=0., SENS2=0.; 253 | if(ms5611_temperature<2000) { 254 | T2=dT*dT/pow(2,31); 255 | OFF2=5*(ms5611_temperature-2000)*(ms5611_temperature-2000)/pow(2,1); 256 | SENS2=5*(ms5611_temperature-2000)*(ms5611_temperature-2000)/pow(2,2); 257 | if(ms5611_temperature<-1500) { 258 | OFF2+=7*(ms5611_temperature+1500)*(ms5611_temperature+1500); 259 | SENS2+=11*(ms5611_temperature+1500)*(ms5611_temperature+1500)/pow(2,1); 260 | } 261 | } 262 | 263 | ms5611_temperature-=T2; 264 | OFF-=OFF2; 265 | SENS-=SENS2; 266 | ms5611_pressure=(((D1*SENS)/pow(2,21)-OFF)/pow(2,15)); 267 | } 268 | 269 | //**************************************************************************/ 270 | // MSL pressure formula 271 | //**************************************************************************/ 272 | double Plugin_032_pressureElevation(double atmospheric, int altitude) { 273 | return atmospheric / pow(1.0 - (altitude/44330.0), 5.255); 274 | } 275 | 276 | -------------------------------------------------------------------------------- /_P006_BMP085.ino: -------------------------------------------------------------------------------- 1 | //####################################################################################################### 2 | //######################## Plugin 006 BMP0685 I2C Barometric Pressure Sensor ########################### 3 | //####################################################################################################### 4 | 5 | #define PLUGIN_006 6 | #define PLUGIN_ID_006 6 7 | #define PLUGIN_NAME_006 "Temperature & Pressure - BMP085" 8 | #define PLUGIN_VALUENAME1_006 "Temperature" 9 | #define PLUGIN_VALUENAME2_006 "Pressure" 10 | 11 | boolean Plugin_006_init = false; 12 | 13 | boolean Plugin_006(byte function, struct EventStruct *event, String& string) 14 | { 15 | boolean success = false; 16 | 17 | switch (function) 18 | { 19 | case PLUGIN_DEVICE_ADD: 20 | { 21 | Device[++deviceCount].Number = PLUGIN_ID_006; 22 | Device[deviceCount].Type = DEVICE_TYPE_I2C; 23 | Device[deviceCount].VType = SENSOR_TYPE_TEMP_BARO; 24 | Device[deviceCount].Ports = 0; 25 | Device[deviceCount].PullUpOption = false; 26 | Device[deviceCount].InverseLogicOption = false; 27 | Device[deviceCount].FormulaOption = true; 28 | Device[deviceCount].ValueCount = 2; 29 | Device[deviceCount].SendDataOption = true; 30 | Device[deviceCount].TimerOption = true; 31 | Device[deviceCount].GlobalSyncOption = true; 32 | break; 33 | } 34 | 35 | case PLUGIN_GET_DEVICENAME: 36 | { 37 | string = F(PLUGIN_NAME_006); 38 | break; 39 | } 40 | 41 | case PLUGIN_GET_DEVICEVALUENAMES: 42 | { 43 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_006)); 44 | strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[1], PSTR(PLUGIN_VALUENAME2_006)); 45 | break; 46 | } 47 | 48 | case PLUGIN_WEBFORM_LOAD: 49 | { 50 | string += F("Altitude [m]:"); 54 | success = true; 55 | break; 56 | } 57 | 58 | case PLUGIN_WEBFORM_SAVE: 59 | { 60 | String elev = WebServer.arg("_p006_bmp085_elev"); 61 | Settings.TaskDevicePluginConfig[event->TaskIndex][1] = elev.toInt(); 62 | success = true; 63 | break; 64 | } 65 | 66 | case PLUGIN_READ: 67 | { 68 | if (!Plugin_006_init) 69 | { 70 | if (Plugin_006_bmp085_begin()) 71 | Plugin_006_init = true; 72 | } 73 | 74 | if (Plugin_006_init) 75 | { 76 | UserVar[event->BaseVarIndex] = Plugin_006_bmp085_readTemperature(); 77 | int elev = Settings.TaskDevicePluginConfig[event->TaskIndex][1]; 78 | if (elev) 79 | { 80 | UserVar[event->BaseVarIndex + 1] = Plugin_006_pressureElevation((float)Plugin_006_bmp085_readPressure() / 100, elev); 81 | } else { 82 | UserVar[event->BaseVarIndex + 1] = ((float)Plugin_006_bmp085_readPressure()) / 100; 83 | } 84 | String log = F("BMP : Temperature: "); 85 | log += UserVar[event->BaseVarIndex]; 86 | addLog(LOG_LEVEL_INFO, log); 87 | log = F("BMP : Barometric Pressure: "); 88 | log += UserVar[event->BaseVarIndex + 1]; 89 | addLog(LOG_LEVEL_INFO, log); 90 | success = true; 91 | } 92 | break; 93 | } 94 | 95 | } 96 | return success; 97 | } 98 | 99 | #define BMP085_I2CADDR 0x77 100 | #define BMP085_ULTRAHIGHRES 3 101 | #define BMP085_CAL_AC1 0xAA // R Calibration data (16 bits) 102 | #define BMP085_CAL_AC2 0xAC // R Calibration data (16 bits) 103 | #define BMP085_CAL_AC3 0xAE // R Calibration data (16 bits) 104 | #define BMP085_CAL_AC4 0xB0 // R Calibration data (16 bits) 105 | #define BMP085_CAL_AC5 0xB2 // R Calibration data (16 bits) 106 | #define BMP085_CAL_AC6 0xB4 // R Calibration data (16 bits) 107 | #define BMP085_CAL_B1 0xB6 // R Calibration data (16 bits) 108 | #define BMP085_CAL_B2 0xB8 // R Calibration data (16 bits) 109 | #define BMP085_CAL_MB 0xBA // R Calibration data (16 bits) 110 | #define BMP085_CAL_MC 0xBC // R Calibration data (16 bits) 111 | #define BMP085_CAL_MD 0xBE // R Calibration data (16 bits) 112 | #define BMP085_CONTROL 0xF4 113 | #define BMP085_TEMPDATA 0xF6 114 | #define BMP085_PRESSUREDATA 0xF6 115 | #define BMP085_READTEMPCMD 0x2E 116 | #define BMP085_READPRESSURECMD 0x34 117 | 118 | uint8_t oversampling = BMP085_ULTRAHIGHRES; 119 | int16_t ac1, ac2, ac3, b1, b2, mb, mc, md; 120 | uint16_t ac4, ac5, ac6; 121 | 122 | /*********************************************************************/ 123 | boolean Plugin_006_bmp085_begin() 124 | /*********************************************************************/ 125 | { 126 | if (Plugin_006_bmp085_read8(0xD0) != 0x55) return false; 127 | 128 | /* read calibration data */ 129 | ac1 = Plugin_006_bmp085_read16(BMP085_CAL_AC1); 130 | ac2 = Plugin_006_bmp085_read16(BMP085_CAL_AC2); 131 | ac3 = Plugin_006_bmp085_read16(BMP085_CAL_AC3); 132 | ac4 = Plugin_006_bmp085_read16(BMP085_CAL_AC4); 133 | ac5 = Plugin_006_bmp085_read16(BMP085_CAL_AC5); 134 | ac6 = Plugin_006_bmp085_read16(BMP085_CAL_AC6); 135 | 136 | b1 = Plugin_006_bmp085_read16(BMP085_CAL_B1); 137 | b2 = Plugin_006_bmp085_read16(BMP085_CAL_B2); 138 | 139 | mb = Plugin_006_bmp085_read16(BMP085_CAL_MB); 140 | mc = Plugin_006_bmp085_read16(BMP085_CAL_MC); 141 | md = Plugin_006_bmp085_read16(BMP085_CAL_MD); 142 | } 143 | 144 | /*********************************************************************/ 145 | uint16_t Plugin_006_bmp085_readRawTemperature(void) 146 | /*********************************************************************/ 147 | { 148 | Plugin_006_bmp085_write8(BMP085_CONTROL, BMP085_READTEMPCMD); 149 | delay(5); 150 | return Plugin_006_bmp085_read16(BMP085_TEMPDATA); 151 | } 152 | 153 | /*********************************************************************/ 154 | uint32_t Plugin_006_bmp085_readRawPressure(void) 155 | /*********************************************************************/ 156 | { 157 | uint32_t raw; 158 | 159 | Plugin_006_bmp085_write8(BMP085_CONTROL, BMP085_READPRESSURECMD + (oversampling << 6)); 160 | 161 | delay(26); 162 | 163 | raw = Plugin_006_bmp085_read16(BMP085_PRESSUREDATA); 164 | raw <<= 8; 165 | raw |= Plugin_006_bmp085_read8(BMP085_PRESSUREDATA + 2); 166 | raw >>= (8 - oversampling); 167 | 168 | return raw; 169 | } 170 | 171 | /*********************************************************************/ 172 | int32_t Plugin_006_bmp085_readPressure(void) 173 | /*********************************************************************/ 174 | { 175 | int32_t UT, UP, B3, B5, B6, X1, X2, X3, p; 176 | uint32_t B4, B7; 177 | 178 | UT = Plugin_006_bmp085_readRawTemperature(); 179 | UP = Plugin_006_bmp085_readRawPressure(); 180 | 181 | // do temperature calculations 182 | X1 = (UT - (int32_t)(ac6)) * ((int32_t)(ac5)) / pow(2, 15); 183 | X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md); 184 | B5 = X1 + X2; 185 | 186 | // do pressure calcs 187 | B6 = B5 - 4000; 188 | X1 = ((int32_t)b2 * ( (B6 * B6) >> 12 )) >> 11; 189 | X2 = ((int32_t)ac2 * B6) >> 11; 190 | X3 = X1 + X2; 191 | B3 = ((((int32_t)ac1 * 4 + X3) << oversampling) + 2) / 4; 192 | 193 | X1 = ((int32_t)ac3 * B6) >> 13; 194 | X2 = ((int32_t)b1 * ((B6 * B6) >> 12)) >> 16; 195 | X3 = ((X1 + X2) + 2) >> 2; 196 | B4 = ((uint32_t)ac4 * (uint32_t)(X3 + 32768)) >> 15; 197 | B7 = ((uint32_t)UP - B3) * (uint32_t)( 50000UL >> oversampling ); 198 | 199 | if (B7 < 0x80000000) 200 | { 201 | p = (B7 * 2) / B4; 202 | } 203 | else 204 | { 205 | p = (B7 / B4) * 2; 206 | } 207 | X1 = (p >> 8) * (p >> 8); 208 | X1 = (X1 * 3038) >> 16; 209 | X2 = (-7357 * p) >> 16; 210 | 211 | p = p + ((X1 + X2 + (int32_t)3791) >> 4); 212 | return p; 213 | } 214 | 215 | /*********************************************************************/ 216 | float Plugin_006_bmp085_readTemperature(void) 217 | /*********************************************************************/ 218 | { 219 | int32_t UT, X1, X2, B5; // following ds convention 220 | float temp; 221 | 222 | UT = Plugin_006_bmp085_readRawTemperature(); 223 | 224 | // step 1 225 | X1 = (UT - (int32_t)ac6) * ((int32_t)ac5) / pow(2, 15); 226 | X2 = ((int32_t)mc * pow(2, 11)) / (X1 + (int32_t)md); 227 | B5 = X1 + X2; 228 | temp = (B5 + 8) / pow(2, 4); 229 | temp /= 10; 230 | 231 | return temp; 232 | } 233 | 234 | /*********************************************************************/ 235 | uint8_t Plugin_006_bmp085_read8(uint8_t a) 236 | /*********************************************************************/ 237 | { 238 | uint8_t ret; 239 | 240 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 241 | Wire.write(a); // sends register address to read from 242 | Wire.endTransmission(); // end transmission 243 | 244 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 245 | Wire.requestFrom(BMP085_I2CADDR, 1);// send data n-bytes read 246 | ret = Wire.read(); // receive DATA 247 | Wire.endTransmission(); // end transmission 248 | 249 | return ret; 250 | } 251 | 252 | /*********************************************************************/ 253 | uint16_t Plugin_006_bmp085_read16(uint8_t a) 254 | /*********************************************************************/ 255 | { 256 | uint16_t ret; 257 | 258 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 259 | Wire.write(a); // sends register address to read from 260 | Wire.endTransmission(); // end transmission 261 | 262 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 263 | Wire.requestFrom(BMP085_I2CADDR, 2);// send data n-bytes read 264 | ret = Wire.read(); // receive DATA 265 | ret <<= 8; 266 | ret |= Wire.read(); // receive DATA 267 | Wire.endTransmission(); // end transmission 268 | 269 | return ret; 270 | } 271 | 272 | /*********************************************************************/ 273 | boolean Plugin_006_bmp085_write8(uint8_t a, uint8_t d) 274 | /*********************************************************************/ 275 | { 276 | Wire.beginTransmission(BMP085_I2CADDR); // start transmission to device 277 | Wire.write(a); // sends register address to read from 278 | Wire.write(d); // write data 279 | if(Wire.endTransmission() != 0) 280 | return false; 281 | 282 | return true; 283 | } 284 | 285 | /*********************************************************************/ 286 | float Plugin_006_pressureElevation(float atmospheric, int altitude) { 287 | /*********************************************************************/ 288 | return atmospheric / pow(1.0 - (altitude/44330.0), 5.255); 289 | } 290 | --------------------------------------------------------------------------------