Here ya go Bob -
Main sketch:
```cpp
/*
Hardware/Web assignments: ID: esp32-EAA4C8 MAC: C4:DD:57:EA:A4:C8
*/
#include "hashtag_includes.h" // see tabs at top
#include "constants.h"
// ***************** VOID SETUP ***************
void setup() {
startup_Millis = millis();
pinMode(System_Alm_LED, OUTPUT); // Onboard Visual Alm Indicator
pinMode(ONBOARD_LED, OUTPUT); // Blink LED function
pinMode(Alarm_Relay, OUTPUT); // Alarm relay
pinMode(Pressure_Switch, INPUT); // Alarm Input
pinMode(Pump_Run_Status, INPUT); // Spare Dry Contacts on 220v pump contactor
pinMode(System_Reset, INPUT); // Reset/clear system alarms
digitalWrite(Alarm_Relay, LOW);
// delay(300000); // allow voltage stabilization on startup & time for routers to reset after a power outage
Serial.begin(115200);
while (WiFi.status() != WL_CONNECTED) {
Initial_Connect_Attempts++;
Serial.println("Attempting to Connect To Local Network: ");
Serial.println(wifissid);
WiFi.begin(wifissid, wifipass);
delay(4000);
if (Initial_Connect_Attempts == 5) {
Serial.println("5 LAN connect attempts unsuccessful; going to connectToWifi()");
connectToWiFi();
}
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");
Serial.println(WiFi.localIP());
Serial.println("Attempting to connect to local WPA network...");
initTime("CST6CDT,M3.2.0,M11.1.0"); // https://sites.google.com/a/usapiens.com/opnode/time-zones
server.begin();
// you're connected now, so print out the status:
Serial.print("WiFi Status: ");
Serial.println(WiFi.status());
Serial.println();
Serial.print("ESP Board MAC Address: ");
Serial.println(WiFi.macAddress());
DS18B20.begin(); // initialize the DS18B20 space sensor
DS18B20.setWaitForConversion(false); // this speeds up processor throughput/execution time
}
void loop() {
UNO_run_cycle_start = millis();
current_Millis = millis();
printLocalTime(); // used to determine midnight reset of "daily" pump counters
// ************************* Processor Run LED ************************
if (current_Millis - previous_LED_Millis >= interval) {
previous_LED_Millis = current_Millis;
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(ONBOARD_LED, ledState);
}
if ((current_Millis - read_Temps_Time) >= read_Temps_interval) { // delay reading DS18B20s to every X seconds for added stability
space_temp_1 = DS18B20.getTempFByIndex(0); // read temperature in °F
read_Temps_Time = current_Millis;
}
DS18B20.requestTemperatures(); // send the command to get temperatures
sp_temp_1 = space_temp_1 + tmp_adj_1; // sensor calibration
pressure_switch_state = digitalRead(Pressure_Switch); //Pressure Switch Input Pin Read
pump_run_contacts = digitalRead(Pump_Run_Status); // spare set of contacts from 220 volt contactor
alarm_reset = digitalRead(System_Reset); // switch input activated by human operator
// ************************* System Alarm LED ************************
if (bldg_alarm_state == true)
if ((current_Millis - system_alm_LED_Millis) >= interval_1) {
system_alm_LED_Millis = current_Millis;
if (Sys_Alm_ledState == LOW) {
Sys_Alm_ledState = HIGH;
} else {
Sys_Alm_ledState = LOW;
}
digitalWrite(System_Alm_LED, Sys_Alm_ledState);
}
// ***************** System Alarm Reset/Clear **************
if (alarm_reset == HIGH) { // reset flags & audibles
strcpy(Bldg_Alarm, "OFF");
strcpy(Alm_Relay, "OFF");
strcpy(Temp_Alm, "OFF");
strcpy(Pump_Alm, "OFF");
strcpy(Pressure_Alm, "OFF");
bldg_alarm_state = false;
bldg_alm_flag = false;
pump_alarm = false;
pump_alarm_state = false;
pressure_alarm = false;
press_alarm_state = false;
alm_temp_hour = 0;
alm_temp_min = 0;
alm_press_hour = 0;
alm_press_min = 0;
alm_pmp_run_hour = 0;
alm_pmp_run_min = 0;
temp_alarm = false;
temp_alarm_state = false;
confirm_temp_alm_state = false;
pump_run_state = false;
highest_space_tmp = 0;
lowest_space_tmp = 80;
digitalWrite(Alarm_Relay, LOW);
digitalWrite(System_Alm_LED, LOW);
delay(2000);
digitalWrite(System_Alm_LED, HIGH); // pulse LED to show reset in process
delay(300);
digitalWrite(System_Alm_LED, LOW);
delay(600);
digitalWrite(System_Alm_LED, HIGH);
delay(300);
digitalWrite(System_Alm_LED, LOW);
delay(600);
digitalWrite(System_Alm_LED, HIGH); // LED stays ON during pump recovery period
delay(20000); // 20 seconds to allow pump time to rebuild line pressure
digitalWrite(System_Alm_LED, LOW);
delay(1000);
digitalWrite(System_Alm_LED, HIGH); // pulse LED to show pump delay period has expired
delay(500);
digitalWrite(System_Alm_LED, LOW);
}
// ***************** Pump Run Time Monitor & Alarm/Report Function ********
if (pump_run_contacts == HIGH) {
pump_ON = true;
pmp_run_state = 1;
pump_OFF_timeHack = false;
pmp_OFF_hr = 0;
pmp_OFF_min = 0;
pmp_OFF_month = 0;
pmp_OFF_day = 0;
strcpy(Pump_Status, "ON");
} else {
pump_ON = false;
pmp_run_state = 0;
strcpy(Pump_Status, "OFF");
}
if (pump_ON == true && pump_run_state == false) {
pump_ON_Millis = current_Millis;
pump_run_state = true;
}
if (pump_ON == true) {
current_pump_cycle = (current_Millis - pump_ON_Millis);
current_pump_cycle_sec = current_pump_cycle / 1000;
current_pump_cycle_min = current_pump_cycle / 60000;
current_pump_cycle_run_min = current_pump_cycle_min % 60;
current_pump_cycle_run_sec = current_pump_cycle_sec % 60;
if (current_pump_cycle >= max_pump_runtime) {
pump_alarm = true;
}
}
if (pump_run_state == true && pump_ON == false) { // timestamp pump turning off
pump_OFF_Millis = current_Millis;
pump_run_state = false;
current_pump_cycle_run_sec = 0;
current_pump_cycle_min = 0;
last_pump_cycle_Millis = pump_OFF_Millis - pump_ON_Millis;
last_pump_cycle_sec = (last_pump_cycle_Millis / 1000);
daily_run_Millis = (last_pump_cycle_Millis + daily_run_Millis);
daily_run_seconds = (daily_run_Millis / 1000); // daily_run_seconds
daily_pump_run_sec = daily_run_seconds % 60;
daily_run_minutes = (daily_run_seconds / 60);
int hr = daily_run_minutes / 60;
}
if (pump_ON == false && pump_OFF_timeHack == false) {
pmp_OFF_hr = time_hour; // TOD = Time of Day [webpage descriptor]
pmp_OFF_min = time_min;
pmp_OFF_month = time_month;
pmp_OFF_day = time_day;
pump_OFF_timeHack = true;
}
if (pmp_run_state != last_pump_state) { // compare the pump run status to its previous state
if (pump_ON == true) // if the state has changed to ON increment the counter;
{ // goal is to only increment counter ONLY when pump comes ON
on_off_cycle_count++;
}
last_pump_state = pmp_run_state; // save current state as last state, for next time thru loop
}
if (counter_reset == true) { // clear daily counters & temp hi/lo at midnight
daily_run_Millis = 0;
daily_run_seconds = 0;
daily_run_minutes = 0;
on_off_cycle_count = 0;
pump_OFF_Millis = 0;
pmp_OFF_interval = 0;
highest_space_tmp = 0;
lowest_space_tmp = 80;
counter_reset = false;
}
if (pump_ON == false) {
pump_alarm = false;
// pump_run_state = false;
// current_pump_cycle = 0;
pump_ON_Millis = 0;
} // ************ Monitor if pump ON too long in one cycle *********
if (pump_alarm == true && pump_alarm_state == false) {
strcpy(Pump_Alm, "ON");
alm_pmp_run_hour = time_hour;
alm_pmp_run_min = time_min;
pump_alarm_state = true;
bldg_alarm_state = true;
sendToPushingBox(DEVID3);
} // ***************** Low Water Pressure Alarm Function ********
if (pressure_switch_state == HIGH) {
delay(5000);
reread_press_switch = digitalRead(Pressure_Switch); // avoid false input reading with a delayed reread
if (reread_press_switch == HIGH) {
pressure_alarm = true;
}
}
if (pressure_alarm == true && press_alarm_state == false) { // check if pressure switch has changed state
strcpy(Pressure_Alm, "ON"); // AND alm state "was" false; this ensures alm is not repeatedly sent to API.
alm_press_hour = time_hour; // timestamp alarm
alm_press_min = time_min;
press_alarm_state = true;
bldg_alarm_state = true;
sendToPushingBox(DEVID2);
}
// ***************** Low Temp Alarm Function ***************
if ((sp_temp_1 <= Low_Tmp_Alm) && confirm_temp_alm_state == false) {
delay(5000);
space_temp_1 = DS18B20.getTempFByIndex(0); // reread temperature after delay to confirm value
DS18B20.requestTemperatures();
if (sp_temp_1 <= Low_Tmp_Alm) {
temp_alarm = true;
confirm_temp_alm_state = true; // temp verified in alarm so lockout temp check
}
}
if (temp_alarm == true && temp_alarm_state == false) {
strcpy(Temp_Alm, "ON");
alm_temp_hour = time_hour; // timestamp alarm
alm_temp_min = time_min;
temp_alarm_state = true; // Send request to PushingBox ONCE when temp alm is true
bldg_alarm_state = true;
sendToPushingBox(DEVID1);
} // *********** Building Alarm/Activate Audible Warning **************
if (bldg_alarm_state == true && bldg_alm_flag == false) {
bldg_alm_flag = true;
digitalWrite(Alarm_Relay, HIGH);
strcpy(Bldg_Alarm, "ON");
strcpy(Alm_Relay, "ON");
if (DEBUG) { Serial.println(" Turn Horn ON & kill pump !!! "); }
}
// *********************** Record Temp High/Low **********************
if (sp_temp_1 >= (highest_space_tmp + .2)) {
highest_space_tmp = sp_temp_1;
}
if (sp_temp_1 <= (lowest_space_tmp - .2)) {
lowest_space_tmp = sp_temp_1;
}
// ******************** WiFiWebServer Code***********
if (WiFi.status() != WL_CONNECTED && current_Millis - startup_Millis > wait_interval) // && millis() - last_Connection_Attempt_At_Ms > 15000ul )
{
WiFi.disconnect(); // last_Connection_Attempt_At_Ms = millis();
delay(2000);
WiFi.begin(wifissid, wifipass);
delay(4000);
restart_Flag = true;
connectToWiFi();
}
if (WiFi.status() == WL_CONNECTED && restart_Flag == true) {
restart_Flag = false;
startup_Millis = millis();
server.begin();
}
int rssi = WiFi.RSSI();
WiFiClient client = server.available(); // listen for incoming clients
if (client) {
Serial.println("new client");
// an http request ends with a blank line
currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n') // && currentLineIsBlank)
{
client.print(" ");
client.print(rssi);
StackString<75> XString = StackString<75>(" dBm Signal Strength [RSSI] ");
XString.append("/ RTC Hr: ");
XString.append(time_hour);
XString.append(" : Min: ");
XString.append(time_min);
XString.append(" : Sec: ");
XString.append(time_sec);
client.println(XString.c_str());
client.println();
StackString<75> YString = StackString<75>(" MAC Address: ");
YString.append(MAC_Address);
YString.append(" / INO Version: ");
YString.append(INO_Version);
YString.append(" / Void Loop (Ms): ");
YString.append(UNO_cycle_time);
client.println(YString.c_str());
client.println();
StackString<75> AString = StackString<75>(" Pump House: ESP WROOM-32");
client.println(AString.c_str());
StackString<75> BString = StackString<75>(" ************************");
client.println(BString.c_str());
client.println();
StackString<75> HString = StackString<75>(" Pump Status = ");
HString.append(Pump_Status);
client.println(HString.c_str());
client.println();
StackString<75> KString = StackString<75>(" Current Pump Cycle [seconds] = ");
KString.append(current_pump_cycle_run_sec);
client.println(KString.c_str());
client.println();
StackString<75> LString = StackString<75>(" Current Pump Cycle [minutes] = ");
LString.append(current_pump_cycle_min);
client.println(LString.c_str());
client.println();
StackString<75> MString = StackString<75>(" Last Pump Cycle [seconds] = ");
MString.append(last_pump_cycle_sec);
client.println(MString.c_str());
client.println();
StackString<75> NString = StackString<75>(" Daily Total Runtime [minutes] = ");
NString.append(daily_run_minutes);
client.println(NString.c_str());
client.println();
StackString<75> PString = StackString<75>(" Daily Total Runtime [seconds] = ");
PString.append(daily_pump_run_sec);
client.println(PString.c_str());
client.println();
StackString<75> OString = StackString<75>(" Daily On-Off Cycles = ");
OString.append(on_off_cycle_count);
client.println(OString.c_str());
client.println();
StackString<95> VString = StackString<95>(" Last Cycle Shut Off [TOD] = Hr: ");
VString.append(pmp_OFF_hr);
VString.append(" Min: ");
VString.append(pmp_OFF_min);
client.println(VString.c_str());
client.println();
StackString<95> WString = StackString<95>(" Last Cycle Shut Off [M/D] = Month: ");
WString.append(pmp_OFF_month);
WString.append(" Day: ");
WString.append(pmp_OFF_day);
client.println(WString.c_str());
client.println();
StackString<75> CString = StackString<75>(" Pump House Temp = ");
CString.append(sp_temp_1);
client.println(CString.c_str());
client.println();
StackString<75> QString = StackString<75>(" Max: ");
QString.append(highest_space_tmp);
QString.append(" Min: ");
QString.append(lowest_space_tmp);
client.println(QString.c_str());
client.println();
StackString<75> DString = StackString<75>(" Temp Alarm Setpoint = ");
DString.append(Low_Tmp_Alm);
client.println(DString.c_str());
client.println();
StackString<75> IString = StackString<75>(" Building Alarm = ");
IString.append(Bldg_Alarm);
client.println(IString.c_str());
client.println();
StackString<75> JString = StackString<75>(" Audible Alarm/Pump Shutdown = ");
JString.append(Alm_Relay);
client.println(JString.c_str());
client.println();
StackString<113> EString = StackString<113>(" Low Temp Alarm = ");
EString.append(Temp_Alm);
EString.append(" Hr: ");
EString.append(alm_temp_hour);
EString.append(" Min: ");
EString.append(alm_temp_min);
client.println(EString.c_str());
client.println();
StackString<93> FString = StackString<93>(" Low Pressure Alarm = ");
FString.append(Pressure_Alm);
FString.append(" Hr: ");
FString.append(alm_press_hour);
FString.append(" Min: ");
FString.append(alm_press_min);
client.println(FString.c_str());
client.println();
StackString<93> GString = StackString<93>(" Pump Continuous Run Alarm = ");
GString.append(Pump_Alm);
GString.append(" Hr: ");
GString.append(alm_pmp_run_hour);
GString.append(" Min: ");
GString.append(alm_pmp_run_min);
client.println(GString.c_str());
break;
}
}
}
delay(2000); // give the web browser time to receive the data
client.stop(); // close the connection:
Serial.println("client disonnected");
}
if (!client.connected() && lastConnected) {
if (DEBUG) { Serial.println(); }
if (DEBUG) { Serial.println(" disconnecting"); }
client.stop();
}
lastConnected = client.connected();
UNO_run_cycle_stop = millis();
UNO_cycle_time = UNO_run_cycle_stop - UNO_run_cycle_start;
}
// **************************** END OF VOID LOOP() ****************************************
void sendToPushingBox(char devid[]) // Function for sending the request to PushingBox
{
client.stop();
delay(2000);
if (DEBUG) { Serial.println(" connecting..."); }
if (client.connect(serverName, 80)) {
if (DEBUG) { Serial.println(" connected"); }
if (DEBUG) { Serial.println(" sending request to PushingBox API"); }
client.print("GET /pushingbox?devid=");
client.print(devid);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(serverName);
client.println("User-Agent: ESP32");
client.println();
} else {
if (DEBUG) { Serial.println(" connection failed"); }
}
}
void setTimezone(const char* timezone) {
Serial.print("Setting Timezone to ");
Serial.println(timezone);
setenv("TZ", timezone, 1);
tzset();
}
void initTime(const char* timezone) {
struct tm timeinfo;
Serial.println("Getting time from NTP server");
configTime(0, 0, "pool.ntp.org"); // First connect to NTP server, use 0 TZ offset
if (!getLocalTime(&timeinfo)) {
Serial.println(" Failed to obtain time");
return;
}
Serial.println("OK, Got the time from NTP");
setTimezone(timezone); // then set your timezone
}
void printLocalTime() { // this function monitors current time of day to initiate
// pump counter reset at midnight
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
return;
}
time_hour = timeinfo.tm_hour; // tm structure element "hour" from time.h
time_min = timeinfo.tm_min; // "minute" " "
time_sec = timeinfo.tm_sec; // "second"
time_month = timeinfo.tm_mon + 1; // + 1 is due to way time.h assigns month values (starts w/ 0)
time_day = timeinfo.tm_mday;
if (time_hour == hour_trigger && time_min == min_trigger && time_sec == sec_trigger) {
Serial.println("Reset counters...");
counter_reset = true;
delay(3000); // used to avoid conflict as time rolls over to new day
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S zone %Z %z ");
Serial.println();
Serial.println("Month [timeinfo.tm_mon] is: ");
Serial.print(time_month);
Serial.println();
}
void connectToWiFi() {
Try_Count = 0;
while (WiFi.status() != WL_CONNECTED) {
Try_Count++;
WiFi.disconnect();
WiFi.begin(wifissid, wifipass);
vTaskDelay(10000);
if (Try_Count == 10) {
Serial.println("..... 10 attempts failed....rebooting processor...");
ESP.restart(); // reboot processor!!!
}
}
// WiFi.onEvent( WiFiEvent ); > define WiFiEvent to do ???
}
Constants.h:
OneWire oneWire(SENSOR_PIN);
DallasTemperature DS18B20(&oneWire);
int status = WL_IDLE_STATUS; // the Wifi radio's status
WiFiClient client;
WiFiServer server(80); // added for testing 2/4
int Initial_Connect_Attempts = 0;
int Try_Count = 0;
char wifissid[18] = "Homestead-LAN_EXT"; // "Homestead-LAN_EXT" for in house testing
char wifipass[13] = "********"; //
char DEVID1[] = "v5A61F203ED29211"; // token/key low temp alarm [ v5A61F203ED29211 ]
char DEVID2[] = "v9072310CAE86043"; // token/key low wtr pressure alarm [ v9072310CAE86043 ]
char DEVID3[] = "va71BBE853590654"; // pump runtime alarm [ va71BBE853590654 ]
char INO_Version[3] = "8S";
char MAC_Address[18] = "C4-DD-57-EA-A4-C8";
int time_month = 0;
int time_day = 0;
int time_hour = 0;
int time_min = 0;
int time_sec = 0;
unsigned long previous_LED_Millis = 0;
const long interval = 1000; // Run LED Blink rate
const long interval_1 = 500; // System Alarm LED blink rate
unsigned long system_alm_LED_Millis = 0;
int UNO_cycle_time = 0;
unsigned long UNO_run_cycle_stop = 0;
unsigned long UNO_run_cycle_start = 0;
int ledState = LOW;
int Sys_Alm_ledState = LOW;
unsigned long startup_Millis = millis(); // static uint32_t last_Connection_Attempt_At_Ms = millis();
unsigned long current_Millis = 0;
int wait_interval = 300000; // 5 minutes of no wifi connection
int hour = 3600000; // 3,600,000 millis per hr
int minute = 60000;
// int min = 60; // 60,000 millis per minute
// int hr = 60;
unsigned long pump_ON_Millis = 0;
unsigned long pump_OFF_Millis = 0;
unsigned long last_pump_cycle_Millis = 0;
int last_pump_cycle_sec = 0;
unsigned long daily_run_Millis = 0;
int daily_run_seconds = 0;
int daily_run_minutes = 0;
int daily_pump_run_sec = 0;
// int daily_run_secs = 0;
// int daily_run_mins = 0;
int current_pump_cycle = 0;
int current_pump_cycle_sec = 0;
int current_pump_cycle_min = 0;
int on_off_cycle_count = 0;
int current_pump_cycle_run_min = 0;
int current_pump_cycle_run_sec = 0;
int last_pump_state = 0;
int pmp_run_stat = 0;
int pmp_run_state = 0;
unsigned long pmp_OFF_interval = 0;
int pmp_OFF_min = 0;
int pmp_OFF_hr = 0;
int pmp_OFF_month = 0;
int pmp_OFF_day = 0;
// static uint32_t pump_alm_stop_Millis = 0;
int max_pump_runtime = 300000; // 5 minutes (300000) maximum run time before an alarm
// static uint32_t pump_runtime = 0;
static bool restart_Flag = false;
boolean DEBUG = true; // Debug mode !!!!
boolean currentLineIsBlank = false; //added 10/31/22 debugging
char serverName[19] = "api.pushingbox.com"; // [ api.pushingbox.com ]
// int keyIndex = 0; WiFi Communication Parameter NEEDED????
const int Alarm_Relay = 4; // Alarm Relay output pinMode(GIOP4/D2, OUTPUT)
int hour_trigger = 23; // hour to reset pump counters to zero
int min_trigger = 59; // minute (23 : 59 : 59)
int sec_trigger = 59; // second HR MIN SEC
boolean counter_reset = false;
boolean bldg_alm_ON = false;
boolean bldg_alarm_state = false;
boolean bldg_alm_flag = false;
boolean temp_alarm = false;
boolean temp_alarm_state = false;
boolean confirm_temp_alm_state = false;
boolean lastConnected = false;
boolean pump_ON = false;
boolean pump_run_state = false;
boolean pump_alarm = false;
boolean pump_OFF_timeHack = false;
int alm_pmp_run_hour = 0;
int alm_pmp_run_min = 0;
// ************* I/O assignments ***********
const int Pressure_Switch = 25; // Board Digital Input GIOP25; pinMode(GIOP#, INPUT);
const int Pump_Run_Status = 22; // Dig Input for pump run status
const int System_Reset = 23; // Reset/clear alarms switch input; GPIO21, D21
const int System_Alm_LED = 32; // Onboard Red LED
int reread_press_switch = 0;
int pressure_switch_state = 0;
int alarm_reset = 0;
int pump_run_contacts = 0;
boolean pressure_alarm = false;
boolean press_alarm_state = false;
boolean pump_alarm_state = false;
int alm_press_hour = 0;
int alm_press_min = 0;
// ***************** Webpage Descrptors ***************
char Pump_Status[4] = "OFF";
char Pump_Alm[4] = "OFF";
char Temp_Alm[4] = "OFF";
char Pressure_Alm[4] = "OFF";
char Alm_Relay[4] = "OFF";
char Bldg_Alarm[4] = "OFF";
// const int B = 4275; // B value of the thermistor; +- 275 = .6 C (1.0 F)
// const uint32_t R0 = 100000; // R0 = 100k; int type uint32_t required (unsigned 32 bit)
unsigned long read_Temps_Time = 0;
unsigned long read_Temps_interval = 5000;
int tmp_adj_1 = 0; // sensor 1 calibration adjustment
float space_temp_1; // Dallas DS18B20 temp sensor
int sp_temp_1;
int alm_temp_hour = 0;
int alm_temp_min = 0;
int Low_Tmp_Alm = 36.00; // Low Alarm Setpoint
int highest_space_tmp = 0;
int lowest_space_tmp = 80;
hashtag_includes.h:
#include <SPI.h>
#include <WiFi.h>
#include <math.h>
#include "time.h"
#include <StackString.hpp> // save memory using this function: character arrays
using namespace Stack;
// #include <DS18B20.h>
#include <OneWireNg.h>
#include <DallasTemperature.h>
#define SENSOR_PIN 14 // ESP32 pin GPIO14; D14 silkscreen connected to DS18B20
#define ONBOARD_LED 2