//####################################################################################################### //#################################### Plugin 128: HC-SR04 (w/Median) ################################### //####################################################################################################### #define PLUGIN_128 #define PLUGIN_ID_128 128 #define PLUGIN_NAME_128 "Ultr. Sensor - HC-SR04 (w/Median)" #define PLUGIN_VALUENAME1_128 "Distance" void Plugin_128_interrupt() ICACHE_RAM_ATTR; boolean Plugin_128_init = false; volatile unsigned long Plugin_128_timer = 0; volatile unsigned long Plugin_128_state = 0; byte Plugin_128_TRIG_Pin = 0; byte Plugin_128_IRQ_Pin = 0; int readcount_128 = 0; float* medianValues_128; boolean Plugin_128(byte function, struct EventStruct *event, String& string) { static byte switchstate[TASKS_MAX]; boolean success = false; switch (function) { case PLUGIN_DEVICE_ADD: { Device[++deviceCount].Number = PLUGIN_ID_128; Device[deviceCount].Type = DEVICE_TYPE_DUAL; Device[deviceCount].VType = SENSOR_TYPE_SINGLE; Device[deviceCount].Ports = 0; Device[deviceCount].PullUpOption = false; Device[deviceCount].InverseLogicOption = false; Device[deviceCount].FormulaOption = false; Device[deviceCount].ValueCount = 1; Device[deviceCount].SendDataOption = true; Device[deviceCount].TimerOption = true; Device[deviceCount].GlobalSyncOption = true; break; } case PLUGIN_GET_DEVICENAME: { string = F(PLUGIN_NAME_128); break; } case PLUGIN_GET_DEVICEVALUENAMES: { strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_128)); break; } case PLUGIN_WEBFORM_LOAD: { byte choice = Settings.TaskDevicePluginConfig[event->TaskIndex][0]; String options[2]; options[0] = F("Value"); options[1] = F("State"); int optionValues[2]; optionValues[0] = 1; optionValues[1] = 2; string += F("Mode:"); if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) { char tmpString[128]; sprintf_P(tmpString, PSTR("Threshold:"), Settings.TaskDevicePluginConfig[event->TaskIndex][1]); string += tmpString; } char tmpString[128]; sprintf_P(tmpString, PSTR("Nbr. Values:"), Settings.TaskDevicePluginConfig[event->TaskIndex][2]); string += tmpString; success = true; break; } case PLUGIN_WEBFORM_SAVE: { String plugin1 = WebServer.arg("plugin_128_mode"); Settings.TaskDevicePluginConfig[event->TaskIndex][0] = plugin1.toInt(); if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) { String plugin2 = WebServer.arg("plugin_128_threshold"); Settings.TaskDevicePluginConfig[event->TaskIndex][1] = plugin2.toInt(); } String plugin3 = WebServer.arg("plugin_128_medianvals"); Settings.TaskDevicePluginConfig[event->TaskIndex][2] = plugin3.toInt(); success = true; break; } case PLUGIN_INIT: { Plugin_128_init = true; pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT); pinMode(Settings.TaskDevicePin2[event->TaskIndex], INPUT_PULLUP); Plugin_128_IRQ_Pin = Settings.TaskDevicePin2[event->TaskIndex]; attachInterrupt(Settings.TaskDevicePin2[event->TaskIndex], Plugin_128_interrupt, CHANGE); if (medianValues_128) delete [] medianValues_128; medianValues_128 = 0; if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) { if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] < 5) Settings.TaskDevicePluginConfig[event->TaskIndex][2] = 5; } if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) { medianValues_128 = new float[Settings.TaskDevicePluginConfig[event->TaskIndex][2]]; for (byte valNr = 0; valNr < Settings.TaskDevicePluginConfig[event->TaskIndex][2]; valNr++) *(medianValues_128 + valNr) = 0; } success = true; break; } case PLUGIN_WRITE: { String log = ""; String command = parseString(string, 1); if (command == F("status")) { if (parseString(string, 2) == F("valuehcsr04")) { success = true; float value = 0; if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) value = *(medianValues_128 + ((int) (Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2))); //select median reading else value = Plugin_128_read(); log = String(F("SW : HCSR04 ")) + String(F(" Send current value: ")); log += value; addLog(LOG_LEVEL_INFO, log); String status = F("SR04 : Distance: "); status += value; SendStatus(event->Source, status); } } break; } case PLUGIN_READ: // If we select value mode, read and send the value based on global timer { if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1) { Plugin_128_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; float value = Plugin_128_read(); String log = F("SR04 : Distance: "); if (value != -1) { if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) { if (readcount_128 >= Settings.TaskDevicePluginConfig[event->TaskIndex][2]) readcount_128 = 0; *(medianValues_128 + readcount_128) = value; readcount_128++; insertionSort(medianValues_128, Settings.TaskDevicePluginConfig[event->TaskIndex][2]); //sort readings value = *(medianValues_128 + ((int) (Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2))); //select median reading } UserVar[event->BaseVarIndex] = value; log += UserVar[event->BaseVarIndex]; log += String(F(" [")) + String(value) + String(F("]")); success = true; } else log += F("No reading!"); addLog(LOG_LEVEL_INFO,log); } break; } case PLUGIN_TEN_PER_SECOND: // If we select state mode, do more frequent checks and send only state changes { Plugin_128_TRIG_Pin = Settings.TaskDevicePin1[event->TaskIndex]; byte state = 0; float value = Plugin_128_read(); if (value != -1) { if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) { if (readcount_128 >= Settings.TaskDevicePluginConfig[event->TaskIndex][2]) readcount_128 = 0; *(medianValues_128 + readcount_128) = value; readcount_128++; insertionSort(medianValues_128, Settings.TaskDevicePluginConfig[event->TaskIndex][2]); //sort readings value = *(medianValues_128 + ((int) (Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2))); //select median reading } if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 2) { if (value < Settings.TaskDevicePluginConfig[event->TaskIndex][1]) state = 1; if (state != switchstate[event->TaskIndex]) { String log = F("SR04 : State "); log += state; addLog(LOG_LEVEL_INFO,log); switchstate[event->TaskIndex] = state; UserVar[event->BaseVarIndex] = state; event->sensorType = SENSOR_TYPE_SWITCH; sendData(event); } } else if (Settings.TaskDevicePluginConfig[event->TaskIndex][0] == 1) { if (Settings.TaskDevicePluginConfig[event->TaskIndex][2] > 0) { if (readcount_128 >= Settings.TaskDevicePluginConfig[event->TaskIndex][2]) readcount_128 = 0; *(medianValues_128 + readcount_128) = value; readcount_128++; insertionSort(medianValues_128, Settings.TaskDevicePluginConfig[event->TaskIndex][2]); //sort readings value = *(medianValues_128 + ((int) (Settings.TaskDevicePluginConfig[event->TaskIndex][2] / 2))); //select median reading } UserVar[event->BaseVarIndex] = value; } } success = true; break; } } return success; } /*********************************************************************/ float Plugin_128_read() /*********************************************************************/ { float value = -1; Plugin_128_timer = 0; Plugin_128_state = 0; noInterrupts(); digitalWrite(Plugin_128_TRIG_Pin, LOW); delayMicroseconds(2); digitalWrite(Plugin_128_TRIG_Pin, HIGH); delayMicroseconds(10); digitalWrite(Plugin_128_TRIG_Pin, LOW); interrupts(); delay(25); // wait for measurement to finish (max 400 cm * 58 uSec = 23uSec) if (Plugin_128_state == 2) { value = (float)Plugin_128_timer / 58; } return value; } /*********************************************************************/ void Plugin_128_interrupt() /*********************************************************************/ { byte pinState = digitalRead(Plugin_128_IRQ_Pin); if (pinState == 1) // Start of pulse { Plugin_128_state = 1; Plugin_128_timer = micros(); } else // End of pulse, calculate timelapse between start & end { Plugin_128_state = 2; Plugin_128_timer = micros() - Plugin_128_timer; } }