diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..265f8aa --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +creds.h diff --git a/README.md b/README.md new file mode 100644 index 0000000..c11d832 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# arduino_utils +selection of snippets/libraries/abstractions for arduino + +Just random collection of loose methods I am working on to use in my projects, constsantly in progress, very dirty, trying to make portable independant abstraction methods as helpers for building apps +No where close to production code diff --git a/button_abs.h b/button_abs.h index 0876a78..a669285 100644 --- a/button_abs.h +++ b/button_abs.h @@ -5,47 +5,77 @@ #define buttons_abs_h -#include +#include // davetcc/TaskManagerIO + +#include // davetcc/ioabstraction #include const int interruptPin = 3; // if motor.h stalldetect, Real interrupt for io expander USES SERIAL RX!!! const int encoderSWPin = 0; const int encoderAPin = 1; const int encoderBPin = 2; + int _maximumEncoderValue = 0; // 128; 0 for non counting mode -int encoderStale = 0; -int encoderLast = -1; -bool encoderHasChange = false; -bool useInt = false; + +int encoderStale = 0; // prev stale value +int encoderLast = -1; // prev value + +bool encoderHasChange = false; // flag enc change +bool useInt = false; // use interrupts, via interruptPin + +long int encoderLastChange = 0; // timestamp of last encoder change +int encoderThrottleDuration = 500; // how long to defer loop for encoder waits + +bool encoderHasPress = false; +bool encoderHasHold = false; +bool debug_enc = true; volatile bool PCFInterruptFlag = false; -void ICACHE_RAM_ATTR onEncoderChange(int newValue) { +void encoderClear(){ + encoderHasPress = false; + encoderHasHold = false; + encoderHasChange = false; + encoderLastChange = millis(); +} + +void IRAM_ATTR onEncoderChange(int newValue) { + // @todo always a false trigger on start + // if(encoderLast < 0){ + // Serial.println("[ENC] init fired"); + // encoderLast = newValue; + // encoderClear(); + // return; // init + // } + if(_maximumEncoderValue > 0){ - Serial.print("[ENCODER] change to "); - Serial.print(newValue); - Serial.print(" from "); - Serial.print(encoderLast); - if(encoderLast == newValue){ - Serial.println("\n"); - return; + if(debug_enc){ + Serial.print("[ENCODER] change to "); + Serial.print(newValue); + Serial.print(" from "); + Serial.print(encoderLast); + if(encoderLast == newValue){ + Serial.println("\n"); + return; + } } bool dir = (encoderLast > newValue); - Serial.println(" dir: " + String(dir ? "CC" : "CW")); + if(debug_enc) Serial.println(" dir: " + String(dir ? "CC" : "CW")); encoderStale = encoderLast; encoderLast = newValue; encoderHasChange = true; } else{ if(newValue == 0){ - Serial.print("[ENCODER] no change"); + if(debug_enc) Serial.print("[ENCODER] no change"); return; } - Serial.print("[ENCODER] change by "); - Serial.print(newValue); + if(debug_enc){ + Serial.print("[ENCODER] change by "); + Serial.print(newValue); + } bool dir = (newValue == 1); - Serial.println(" dir: " + String(dir ? "CW" : "CC")); // for plotting use 10,20 etc - + if(debug_enc) Serial.println(" dir: " + String(dir ? "CW" : "CC")); // for plotting use 10,20 etc encoderStale = encoderLast; encoderLast = newValue; encoderHasChange = true; @@ -55,7 +85,11 @@ void ICACHE_RAM_ATTR onEncoderChange(int newValue) { void ICACHE_RAM_ATTR onEncoderSWPressed(uint8_t pin, bool heldDown) { Serial.print("[ENCODER] Button "); Serial.println(heldDown ? "Held" : "Pressed"); + encoderHasPress = true; + encoderHasHold = heldDown; } + + // adjust the encoder acceleraton // HWACCEL_FAST // HWACCEL_SLOWER @@ -68,7 +102,7 @@ void setEncoderAccel(HWAccelerationMode accel){ void init_encoder(int encoderAPin, int encoderBPin, int encoderSWPin,uint8_t addr=0){ if(addr){ - // First we set up the switches library, giving it the task manager and tell it where the pins are located + // First we set up the switches library, giving it the task manager and tell it where the pins are located // We could also of chosen IO through an i2c device that supports interrupts. // the second parameter is a flag to use pull up switching, (true is pull up). if(useInt)switches.initialiseInterrupt(ioFrom8574(0x20, interruptPin), true); @@ -79,7 +113,10 @@ void init_encoder(int encoderAPin, int encoderBPin, int encoderSWPin,uint8_t add } // encoder sw + #ifndef ENC_SW_ANALOG switches.addSwitch(encoderSWPin, onEncoderSWPressed); // encoder button press + #endif + // encoder setupRotaryEncoderWithInterrupt(encoderAPin, encoderBPin, onEncoderChange); if(_maximumEncoderValue > 0) switches.changeEncoderPrecision(_maximumEncoderValue, 0); @@ -92,7 +129,6 @@ void init_encoder(int encoderAPin, int encoderBPin, int encoderSWPin,uint8_t add // interrupt for any // taskManager.setInterruptCallback(onInterrupt); - // now we add the switches, we dont want the spinwheel button to repeat, so leave off the last parameter // which is the repeat interval (millis / 20 basically) Repeat button does repeat as we can see. @@ -103,6 +139,15 @@ void setEncoderMax(int maximumEncoderValue){ _maximumEncoderValue = maximumEncoderValue; } +void checkAnalogSW(uint8_t pin, uint16_t value,uint32_t hold){ + // adc range / value 1024/500 = 2 states+ etc + if(analogRead(pin) < value){ + encoderHasPress = true; + delay(hold); + if(analogRead(pin) < value) encoderHasHold = true; + } +} + // IoAbstractionRef iodev = switches.getIoAbstraction(); // iodev->pinDirection(7,OUTPUT); // bool res = iodev->runLoop(); diff --git a/buzzer.h b/buzzer.h index 86fa48d..dd58b9e 100644 --- a/buzzer.h +++ b/buzzer.h @@ -1,127 +1,258 @@ #ifndef buzzer_h #define buzzer_h -#include -#include -ESP8266_Tones BUZZER_TONE(BUZ_PIN); -char szBuf[128]; // serial buffer seems to be only 128 bytes on ESP, only 64 on ATmega - -#include // requires #include -// define the pin used and initialize a MusicEngine object -MmlMusicPWM BUZZER_MUSIC(BUZ_PIN); int BUZZ_VOLUME = 100; +int buzzer_pin = -1; -bool init_buzzer(){ - pinMode(BUZ_PIN,OUTPUT); -} +// #ifdef ESP8266 -void soundSiren(int nTimes=10) -{ - for(int nLoop=0; nLoop100; nFreq-=10) - { - BUZZER_MUSIC.tone(nFreq); - delay(1); - } - } -} +// #include // https://github.com/Mottramlabs/ESP8266-Tone-Generator +// #include +// ESP8266_Tones BUZZER_TONE(BUZ_PIN); +// char szBuf[128]; // serial buffer seems to be only 128 bytes on ESP, only 64 on ATmega -void soundNoise(int nLength=30) -{ - srand(analogRead(A0)); - for(int nLoop=0; nLoop // requires #include +// // define the pin used and initialize a MusicEngine object +// MmlMusicPWM BUZZER_MUSIC(BUZ_PIN); -void soundNoise2(int nLength=20) -{ - srand(analogRead(A0)); - for(int nLoop=0; nLoop100; nFreq-=10) +// { +// BUZZER_MUSIC.tone(nFreq); +// delay(1); +// } +// } +// } -void testsounds() { - // put your setup code here, to run once: - BUZZER_MUSIC.play("T240 L16 O8 r1 CDEDC"); // give a short blurp - // soundSiren(5); - BUZZER_MUSIC.play("T240 L32 O8 r1 GDECBADGECDEDCr2GDECBADGECDEDCr1GDECBADGECDEDC"); // play a different noise - // soundNoise(); - // delay(500); - // soundNoise2(); - // delay(500); - // soundNoise3(); - BUZZER_MUSIC.play("T240 L2 O2 r1 CDCECBrCDCDCD O1 r CDCDCDrCDCECB O0 r CDCDCDrCDCECB"); // play a different noise -} +// void soundNoise(int nLength=30) +// { +// srand(analogRead(A0)); +// for(int nLoop=0; nLoopC, T240 O4 L32 CBA V0 A \0\0")); // give a short beep +// } + +// void blurp4(){ +// BUZZER_MUSIC.play("T240 O8 E64"); // give a short beep +// } + +// void blurp5(){ +// BUZZER_MUSIC.play("V20 T240 O8 G64\0\0"); // give a short beep +// // BUZZER_MUSIC.play("T240 O8 G64\0\0"); // give a short beep +// } -void blurp() { - BUZZER_MUSIC.play("V10 T240 L16 O8 CDEDC"); // give a short blurp +// void blurp6(){ +// BUZZER_MUSIC.play("V5 T250 L64 O7 B"); +// } + +// void playBlurpA(){ +// blurp5(); +// delay(50); +// blurp5(); +// delay(50); +// blurp5(); +// delay(50); +// } + +// void chime(){ +// blurp4(); +// } + +// void soundalarm(){ +// for(int i=0; i<6; i++){ +// blurp6(); +// delay(50); +// } +// } + +// #else + +// #include +#include "pitches.h" + +#define BUZ_CHAN 0 + +void plugged() { + // usb melody + tone(buzzer_pin, NOTE_C5, 150); // F6 + tone(buzzer_pin, NOTE_A5, 100); // F5 + tone(buzzer_pin, NOTE_F4, 100); // F5 + tone(buzzer_pin, NOTE_E5, 200); // F5 + noTone(buzzer_pin); +} // End of beep + +void Chirp() { + tone(buzzer_pin, NOTE_A7, 10); // F6 + tone(buzzer_pin, NOTE_C8, 20); // F5 + noTone(buzzer_pin); +} // End of beep + +void Bleep() { + tone(buzzer_pin, NOTE_C7, 50); // F6 + tone(buzzer_pin, NOTE_C8, 100); // F5 +} // End of beep + +void Tone_Down() { + tone(buzzer_pin, NOTE_F6, 200); // F6 + tone(buzzer_pin, NOTE_F5, 200); // F5 + tone(buzzer_pin, NOTE_C6, 200); // C6 +} // End of beep + +void Tone_Up() { + tone(buzzer_pin, NOTE_C6, 200); // C6 + tone(buzzer_pin, NOTE_F5, 200); // F5 + tone(buzzer_pin, NOTE_F6, 200); // F6 +} // End of beep + +void buzzer_test() { + Chirp(); + delay(500); + Bleep(); + delay(500); + Tone_Down(); + delay(500); + Tone_Up(); + delay(500); + + tone(buzzer_pin, NOTE_C4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_D4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_E4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_F4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_G4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_A4, 500); + noTone(buzzer_pin); + tone(buzzer_pin, NOTE_B4, 500); + noTone(buzzer_pin); } -void blurp2() { - BUZZER_MUSIC.play("T240 L16 O8 r1 CDEDC"); // give a short blurp +// #include + +void init_buzzer(int pin){ + buzzer_pin = pin; + // pinMode(buzzer_pin,OUTPUT); + // setToneChannel(BUZ_CHAN); + setToneChannel(BUZ_CHAN); } -void blurp3(){ - BUZZER_MUSIC.play_P(PSTR("T240 O4 L64 AB>C, T240 O4 L32 CBA V0 A \0\0")); // give a short beep +void init_buzzer(){ + init_buzzer(BUZ_PIN); } -void blurp4(){ - BUZZER_MUSIC.play("T240 O8 E64"); // give a short beep +void buzzer_test_DAC(){ + analogWrite(buzzer_pin,100); + delay(500); + analogWrite(buzzer_pin,1200); + delay(500); + analogWrite(buzzer_pin,0); } -void blurp5(){ - BUZZER_MUSIC.play("V20 T240 O8 G64\0\0"); // give a short beep - // BUZZER_MUSIC.play("T240 O8 G64\0\0"); // give a short beep +void buzzer_test_tone(){ + setToneChannel(BUZ_CHAN); + tone(buzzer_pin, NOTE_A7, 10); // F6 + tone(buzzer_pin, NOTE_C8, 20); // F5 + noTone(buzzer_pin); } -void blurp6(){ - BUZZER_MUSIC.play("V5 T250 L64 O7 B"); +void chime(){ + analogWrite(buzzer_pin,100); + delay(500); + analogWrite(buzzer_pin,200); + delay(500); + analogWrite(buzzer_pin,400); + delay(500); + analogWrite(buzzer_pin,800); + delay(500); + analogWrite(buzzer_pin,1200); + delay(500); + analogWrite(buzzer_pin,0); } -void playBlurpA(){ - blurp5(); - delay(50); - blurp5(); - delay(50); - blurp5(); - delay(50); +void soundalarm(){ + Bleep(); + delay(500); + Bleep(); + delay(500); + Bleep(); + delay(500); } -#endif +#endif \ No newline at end of file diff --git a/classes/grapher/about.h b/classes/grapher/about.h deleted file mode 100644 index bdf9e59..0000000 --- a/classes/grapher/about.h +++ /dev/null @@ -1,55 +0,0 @@ -about.h - - -create graph - -init - -id -width -height -x coord -y coord - -axis x -axis y -labels - -precision - -styles - - border - background - - -gridlines -colors - gridlines minor/major/base - grid x, interval, range - grid y - grid logarithmic, extended - grid close ( adds closing gridline , looks better if no border) - - -labels - on/off, - padding - size (graphics lib dependant) - -sublclass traces - -id -y upper limit -y lower limit -y scaler* - -color -segment colors* - -style - dashed - dots - -fills, area under/over - diff --git a/classes/grapher/grapher.cpp b/classes/grapher/grapher.cpp deleted file mode 100644 index a42e0c1..0000000 --- a/classes/grapher/grapher.cpp +++ /dev/null @@ -1,390 +0,0 @@ -#include "grapher.h" - - -grapher::~grapher(int width = 0, int height = 0, int xPos = 0, int yPos = 0){ - _x = xPos; - _y = yPos; - _w = width; - _h = height; - - init_graph(); -} - -// candidate for class -grapher::init_graph(){ - - // class vars - xPos = _x; - yPos = _y; - width = _w; - height = _h; - - double x, y; - - // use full size - // setup basic inputs, x,y and W,h, add padding automatically if showing axis, and auto compensate for graph function y offset bottom left! - - // int height; - // int width; - bool invertWH = false; - - if(width == 0 && height == 0){ - width = TFT_WIDTH; //240; - height = TFT_HEIGHT; // 320; - invertWH = true; - } - - // invert width height (tft_eSPI uses shortend wide for some reason) - if(invertWH){ - int _height = height; - height = width; - width = _height; - } - - // init defaults - Serial.println("[GRAPH] init w:" + (String)width + " h: " + (String)height); - // int xPos = 0; - // int yPos = 0; - - // @todo add better clamping for display size - // if xpos + width > tft.width - // if ypos + height > tft.height - width -= xPos+1; // reduce width kludge - // height -= yPos+1; - - Serial.println("[GRAPH] init x:" + (String)width + " y: " + (String)height); - - // axis padding - bool xaxis = false; // show xaxis padding - bool yaxis = false; // show yaxis padding - int xaxispad = 20; // set padding for graph when xaxis shown - int yaxispad = 16; - - int16_t graph_w = width; // temp vars, edit in place - int16_t graph_h = height; - - int graphOff_x = xPos; - int graphOff_y = yPos+height; // translate y position from TL to BL relative - - if(xaxis){ - graph_w += -xaxispad; - graphOff_x += xaxispad; - } - if(yaxis){ - graph_h += -yaxispad; - graphOff_y += -yaxispad; - } - - // data set - double _x = 0; // x = x data point - double _y = 0; // y = y datapont - byte dp = 0; // dp = decimal place precision - double gx = graphOff_x; // gx = x graph location (top left) - double gy = graphOff_y; // gy = y graph location (bottom left) - double w = graph_w; // w = width of graph - double h = graph_h; // h = height of graph - - // @todo make grid value based not pixel, stupid - double xlo = 0; // xlo = lower bound of x axis - x scale min - double xhi = 100; // xhi = upper bound of x axis - x scale max - double xinc = 5; // xinc = division of x axis (pixels not count) - - int xgridpx = (h/(xhi-xlo))*xinc; - - double ylo = 0; // ylo = lower bound of y axis - y scale min - double yhi = 100; // yhi = upper bound of y axis - y scale max - double yinc = 5; // yinc = division of y axis (pixels not count) - - int ygridpx = (w/(yhi-ylo))*yinc; - - char *title = ""; // title = title of graph - char *xlabel = "x"; // xlabel = x asis label - char *ylabel = "y"; // ylabel = y asis label - boolean &redraw = display1; // &redraw = flag to redraw graph on first call only - - unsigned int color = PURPLE; // color = plotted trace colour - unsigned int bgcolor = bcolor; - - Serial.println("[GRAPH] grid x px: " + (String)xgridpx); - Serial.println("[GRAPH] grid y px: " + (String)ygridpx); - - // draw background to overwrite previous traces - int padding = 3; // we add bg padding so you can see traces at 0 and max - tft.fillRect((int16_t)xPos,(int16_t)yPos-padding,(int16_t)w,(int16_t)h+(padding*2),bgcolor); - // drawBorder(RED); - Graph(tft, _x, _y, dp, gx, gy, w, h, xlo, xhi, xinc, ylo, yhi, yinc, title, xlabel, ylabel,redraw, color); - // Graph(tft, x, y, 2, 30, 135-8, 240-30, 135-8, 0, 6.5, 1, -1, 1, .25, "x", "y", "", display1, YELLOW); -} - - -void Graph(RM_tft &tft, double x, double y, byte dp, - double gx, double gy, double w, double h, - double xlo, double xhi, double xinc, - double ylo, double yhi, double yinc, - char *title, char *xlabel, char *ylabel, - boolean &redraw, unsigned int pcolor) { - - double ydiv, xdiv; - double i; - double temp; - int rot, newrot; - - _h = h; - _w = w; - _gx = gx; - _gy = gy; - - syncGraphInstance(graphID); - - bool drawXbaseline = false; - bool drawYbaseline = false; - - if (redraw == true) { - - bool showaxis_x = true; // @NI - bool showaxis_y = true; // @NI - - // redraw = false; - // initialize old x and old y in order to draw the first point of the graph - // but save the transformed value - // note my transform funcition is the same as the map function, except the map uses long and we need doubles - //ox = (x - xlo) * ( w) / (xhi - xlo) + gx; - //oy = (y - ylo) * (gy - h - gy) / (yhi - ylo) + gy; - - // tft.setTextDatum(MR_DATUM); - - // draw y scale - for ( i = ylo; i <= yhi; i += yinc){ - // compute the transform - temp = (i - ylo) * (gy - h - gy) / (yhi - ylo) + gy; //posy - - if (i == 0 && drawYbaseline) { - tft.drawLine(gx, temp, gx + w, temp, acolor); // Y a line - tft.setTextColor(lcolor, bcolor); - // tft.drawString(xlabel, (int)(gx + w -q 8) , (int)temp, 2); // x axis label - } - else { - tft.drawLine(gx, temp, gx + w, temp, gcolor); - } - - // draw the y axis values - int yvalpad = 4; // will not go negative ( might depend on driver and buffer though ) - int yvalsize = 1; - // tft.setTextColor(tcolor, bcolor); - tft.setTextColor(tcolor); - // precision is default Arduino--this could really use some format control - // if(dp>0) tft.drawFloat(i, dp, gx - yvalpad, temp, yvalsize); // y axis value labels w padding - // else tft.drawString((String)(int)round(i),(int)(gx - yvalpad), (int)temp, yvalsize); - } - - // draw x scale - for (i = xlo; i <= xhi; i += xinc) { - - // compute the transform - temp = (i - xlo) * ( w) / (xhi - xlo) + gx; // posx - if (i == 0 && drawXbaseline ) { - tft.drawLine(temp, gy, temp, gy - h, acolor); // Y a-line @todo draws on top of y values - tft.setTextColor(lcolor, bcolor); - // tft.setTextDatum(BC_DATUM); - // tft.drawString(ylabel, (int)temp, (int)(gy - h - 8) , 2); // y axis label BT-height w padding, @todo rotate - } - else { - tft.drawLine(temp, gy, temp, gy - h, gcolor); - } - - // Serial.println(i); - // Serial.println(xhi); - // Serial.println(xinc); - // Serial.println((String)abs(xhi/xinc)); - // Close graph grid, @todo add actual border options - // if(i == abs(xhi/xinc)){ - if(i!= xhi && i == abs(xhi/xinc)){ - tft.drawLine(gx + w, gy, gx + w, gy - h, gcolor); // Y end line (w-1?) - } - - // draw the x axis values - int xvalpad = 7; - int xvalsize = 1; - // tft.setTextColor(tcolor, bcolor); - tft.setTextColor(tcolor); - // tft.setTextDatum(TC_DATUM); - // precision is default Arduino--this could really use some format control - // drawFloat(float floatNumber, uint8_t dp, int32_t poX, int32_t poY, [puint8_t font]) - // if(dp>0)tft.drawFloat(i, dp, temp, gy + xvalpad, xvalsize); // x axis value labels w padding - // else tft.drawString((String)(int)round(i),(int)temp,(int)(gy + xvalpad), xvalsize); // v pad +7, fontsize 1 - } - - //draw graph title - tft.setTextColor(tcolor, bcolor); - // tft.drawString(title, (int)(gx + w / 2) , (int)(gy - h - 30), 4); // x axis label - } - - -/** - * [addPoint description] - * @param tft tft instance - * @param id trace id (hardcoded 0-6 ATM) - * @param x x coord - * @param y y coord - * @param xlo x lo - * @param xhi x high - * @param ylo y lo - * @param yhi y high - * @param pcolor point color - */ -void addPoint(RM_tft &tft, int id, double x, double y, - double xlo, double xhi, - double ylo, double yhi, - unsigned int pcolor, int size = 0) -{ - - if(_DEBUG_POINT){ - Serial.print("\n[GRAPH] ADDPOINT id: "+(String)id+ " x - y: "); - Serial.print(x); - Serial.print(" - "); - Serial.println(y); - } - - setGraphInstance(graphID); - - double w = _w; - double h = _h; - double gx = _gx; - double gy = _gy; - bool doubleLine = false; - - // the coordinates are now drawn, plot the data - // the entire plotting code are these few lines... - // recall that ox and oy are initialized above - x = (x - xlo) * ( w) / (xhi - xlo) + gx; - y = (y - ylo) * (gy - h - gy) / (yhi - ylo) + gy; - - if ((x < gx) || (x > gx+w)) {return;} - if ((y < gy-h) || (y > gy)) {return;} - - double ox = getGraphLine(id,0); - double oy = getGraphLine(id,1); - - if(_DEBUG_POINT){ - Serial.print("\n[GRAPH] x - y: "); - Serial.print(x); - Serial.print(" - "); - Serial.println(y); - Serial.print("\n[GRAPH] ox - oy: "); - Serial.print(ox); - Serial.print(" - "); - Serial.println(oy); - - Serial.print("\n[GRAPH] gx - gy: "); - Serial.print(gx); - Serial.print(" - "); - Serial.println(gy); - Serial.println("------"); - Serial.println("DrawLine"); - Serial.flush(); - } - - tft.drawLine(ox, oy, x, y, pcolor); // STILL DOUBLE! - - // drawing 2 more lines to give the graph some thickness - if(size>1){ - tft.drawLine(ox, oy + 1, x, y + 1, pcolor); - tft.drawLine(ox, oy - 1, x, y - 1, pcolor); - } - - // store last point - setGraphLine(id,x,y); - // ox = x; - // oy = y; -} - - -/** - * [addPointSet description] - * @param {[type]} int id [description] - * @param {[type]} int sample [description] - * @param {[type]} double value [description] - * @param {[type]} int numSamples [description] - * @param {Number} int vsize [description] - * @param {Number} int size [description] - */ -void addPointSet(int id, int sample, double value, int numSamples,int vsize = 100,int size = 1,int yindexstart = 0){ - // if(id != filteredId && filteredId >= 0) return; - if(_DEBUG_POINT){ - Serial.println("addPointSet"); - Serial.println(id); - Serial.println(sample); - Serial.println(value); - } - int i = sample; - // int vsize = 100; - // if(sample=0) addPoint(tft,id, 0, 0 , 0, numSamples, 0, vsize, getLineColor(0,0)); // @FIXME does not show up , must add 0 point - // int yindexstart = 65; // start Y at non 0 value - unsigned int c = WHITE; - if(size==0){ - size = 2; - c = GRAY; - } - else c = getLineColor(id,0); - addPoint(tft,id, i, value , 0, numSamples, yindexstart, vsize, c,size); - - // addPoint(tft,id, i, ((abs(vsize/numSamples))*(i)) , 0, numSamples, 0, vsize, getLineColor(i-1,0)); -} - - -void test_trace_sin(){ - double x, y; - for (x = 0; x <= 6.3; x += .1) { - y = sin(x); - // Trace(tft, x, y, 1, 60, 290, 390, 260, 0, 6.5, 1, -1, 1, .25, "Sin(x)", "x", "fn(x)", update1, YELLOW); - addPoint(tft, 0,x, y, 0, 6.5, -1, 1, YELLOW); - // Graph(tft, x, y, dp, gx, gy, w, h, xlo, xhi, xinc, ylo, yhi, yinc, title, xlabel, ylabel,redraw, color); - delay(100); - } -} - -void test_trace(uint32_t c){ - double x, y; - for (x = 0; x <= 100; x += 10) { - // addPoint(RM_tft &tft, int id, double x, double y,double xlo, double xhi,double ylo, double yhi,unsigned int pcolor) - // addPoint(RM_tft &tft, id, x, y, xlo, xhi ylo, yhi, color) - addPoint(tft, 0,x, x, 0, 100, 0, 100, c); - delay(100); - } -} - -// add a bunch of traces for testing -void testTraces(int sample){ - return; - int ssize = 240; - int vsize = 100; - int numTraces = 4; - for(int i=0;i + // requires #include + + + +soligen2010/encoder + +"Adafruit_MAX31855.h" + + +// NI #include // @todo test quickstats, add child class for container +// NI #include // https://github.com/provideyourown/statistics + + + +ArduinoBufferedStreams +stream buffer +https://github.com/paulo-raca/ArduinoBufferedStreams + diff --git a/encoder.h b/encoder.h index 099e6cd..6f84d95 100644 --- a/encoder.h +++ b/encoder.h @@ -3,6 +3,7 @@ * // https://github.com/soligen2010/encoder */ #include +// : error: 'ClickEncoder::buttonHeldEnabled' will be initialized after [-Werror=reorder] #define ENCODER_PINA 2 // not working #define ENCODER_PINB 16 // working diff --git a/httpd.h b/httpd.h index ccb222f..4f094fb 100644 --- a/httpd.h +++ b/httpd.h @@ -1,41 +1,61 @@ -#include +#include "wifi_funcs.h" #include -#include -#include +#ifdef ESP8266 +#include ESP8266WebServer server(80); +#elif defined ESP32 +#include +WebServer server(80); +#endif + void handleRoot() { if(server.hasArg(F("ledindex"))){ - Serial.println("has arg ledindex"); + Logger.println("has arg ledindex"); String pixel = server.arg(F("ledindex")); // ledIndex = pixel; - setPixel(pixel.toInt()); + // setHTTPValue(pixel.toInt()); // strip.setPixelColor(pixel.toInt(),strip.Color(255,0,0)); - Serial.println("Setting pixel:" + (String)pixel); + Logger.println("Setting pixel:" + (String)pixel); // strip.show(); // delay(2000); server.send(200, "text/plain", "hello from esp8266! ledindex SET"); } if(server.hasArg(F("pwm"))){ - Serial.println("has arg PWM"); + Logger.println("has arg PWM"); String pwmvalue = server.arg(F("pwm")); // ledIndex = pixel; // setPWM(pwmvalue.toInt()); // strip.setPixelColor(pixel.toInt(),strip.Color(255,0,0)); - Serial.println("Setting PWM:" + (String)pwmvalue); + Logger.println("Setting PWM:" + (String)pwmvalue); + // strip.show(); + // delay(2000); + // server.send(200, "text/plain", "hello from esp8266! PWM set:" + (String)getPWM()); + // analogWrite(16,pwmvalue.toInt()); + setHTTPValue(pwmvalue); + } + + if(server.hasArg(F("freq"))){ + Logger.println("has arg FREQ"); + String pwmvalue = server.arg(F("freq")); + // ledIndex = pixel; + // setPWM(pwmvalue.toInt()); + // strip.setPixelColor(pixel.toInt(),strip.Color(255,0,0)); + Logger.println("Setting FREQ:" + (String)pwmvalue); // strip.show(); // delay(2000); // server.send(200, "text/plain", "hello from esp8266! PWM set:" + (String)getPWM()); // analogWrite(16,pwmvalue.toInt()); - setPWM(pwmvalue); + setHTTPValueB(pwmvalue); } // digitalWrite(LED_BUILTIN, 1); - server.send(200, "text/plain", "hello from esp8266!"); + // server.send(200, "text/plain", "hello from esp8266!"); + server.send(200, "text/plain", "hello from " + getHostname()); // digitalWrite(LED_BUILTIN, 0); } @@ -58,7 +78,7 @@ void handleNotFound() { void httpd_init(){ if (MDNS.begin("esp8266")) { - Serial.println("MDNS responder started"); + Logger.println("[MDNS] responder started"); } server.on("/", handleRoot); @@ -86,10 +106,12 @@ void httpd_init(){ }); server.begin(); - Serial.println("HTTP server started"); + Logger.println("[HTTP] server started"); } void httpd_process(void) { server.handleClient(); + #ifdef ESP8266 MDNS.update(); + #endif } diff --git a/httpportal.h b/httpportal.h new file mode 100644 index 0000000..925a0eb --- /dev/null +++ b/httpportal.h @@ -0,0 +1,42 @@ +#ifndef httpportal_h +#define httpportal_h + +// @USES wifimanager portal + +#include +#include + +WiFiManager portal(Logger); // use netlog for logging wm +// WiFiManager portal; + +void begin_httpportal(){ + // portal.setDebugLevel(); + // portal.setDebugOutput(true); + portal.startWebPortal(); +} + +void stop_httpportal(){ + portal.stopWebPortal(); +} + +void process_httpportal(){ + portal.process(); +} + +void init_httpportal(String title = "",bool begin = true){ + portal.setDebugOutput(true,"[HTTPD] "); + // invert theme, dark + portal.setDarkMode(true); + std::vector menu = {"wifi","param","info","sep","update","restart","exit"}; + portal.setMenu(menu); // custom menu, pass vector + portal.setTitle(title); + // portal.setBackButton(true); + // portal.setHostname(getHostname()); + if(begin) begin_httpportal(); +} + +void begin_httpportalap(){ + portal.startConfigPortal(); +} + +#endif diff --git a/i2c_identify.h b/i2c_identify.h new file mode 100644 index 0000000..9e68f6f --- /dev/null +++ b/i2c_identify.h @@ -0,0 +1,181 @@ +I2CDiscoverDevice + +enum { + DEVICE_UNKNOWN = 0, + DEVICE_SSD1306, + DEVICE_SH1106, + DEVICE_VL53L0X, + DEVICE_BMP180, + DEVICE_BMP280, + DEVICE_BME280, + DEVICE_MPU6000, + DEVICE_MPU9250, + DEVICE_MCP9808, + DEVICE_LSM6DS3, + DEVICE_ADXL345, + DEVICE_ADS1115, + DEVICE_MAX44009, + DEVICE_MAG3110, + DEVICE_CCS811, + DEVICE_HTS221, + DEVICE_LPS25H, + DEVICE_LSM9DS1, + DEVICE_LM8330, + DEVICE_DS3231, + DEVICE_LIS3DH, + DEVICE_LIS3DSH, + DEVICE_INA219, + DEVICE_SHT3X, + DEVICE_HDC1080, + DEVICE_MPU6886, + DEVICE_BME680 +}; + +int I2CReadRegister(BBI2C *pI2C, uint8_t iAddr, uint8_t u8Register, uint8_t *pData, int iLen){ + +} + +// Figure out what device is at that address +// returns the enumerated value +// +int I2CDiscoverDevice(BBI2C *pI2C, uint8_t i) +{ +uint8_t j, cTemp[8]; +int iDevice = DEVICE_UNKNOWN; + + if (i == 0x3c || i == 0x3d) // Probably an OLED display + { + I2CReadRegister(pI2C, i, 0x00, cTemp, 1); + cTemp[0] &= 0xbf; // mask off power on/off bit + if (cTemp[0] == 0x8) // SH1106 + iDevice = DEVICE_SH1106; + else if (cTemp[0] == 3 || cTemp[0] == 6) + iDevice = DEVICE_SSD1306; + return iDevice; + } + if (i >= 0x40 && i <= 0x4f) // check for TI INA219 power measurement sensor + { + I2CReadRegister(pI2C, i, 0x00, cTemp, 2); + if (cTemp[0] == 0x39 && cTemp[1] == 0x9f) + return DEVICE_INA219; + } +// else if (i == 0x5b) // MLX90615? +// { +// I2CReadRegister(pI2C, i, 0x10, cTemp, 3); +// for (j=0; j<3; j++) Serial.println(cTemp[j], HEX); +// } + // try to identify it from the known devices using register contents + { + // Check for TI HDC1080 + I2CReadRegister(pI2C, i, 0xff, cTemp, 2); + if (cTemp[0] == 0x10 && cTemp[1] == 0x50) + return DEVICE_HDC1080; + + // Check for BME680 + if (i == 0x76 || i == 0x77) + { + I2CReadRegister(pI2C, i, 0xd0, cTemp, 1); // chip ID + if (cTemp[0] == 0x61) // BME680 + return DEVICE_BME680; + } + // Check for VL53L0X + I2CReadRegister(pI2C, i, 0xc0, cTemp, 3); + if (cTemp[0] == 0xee && cTemp[1] == 0xaa && cTemp[2] == 0x10) + return DEVICE_VL53L0X; + + // Check for CCS811 + I2CReadRegister(pI2C, i, 0x20, cTemp, 1); + if (cTemp[0] == 0x81) // Device ID + return DEVICE_CCS811; + + // Check for LIS3DSH accelerometer from STMicro + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); + if (cTemp[0] == 0x3f) // WHO_AM_I + return DEVICE_LIS3DSH; + + // Check for LIS3DH accelerometer from STMicro + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); + if (cTemp[0] == 0x33) // WHO_AM_I + return DEVICE_LIS3DH; + + // Check for LSM9DS1 magnetometer/gyro/accel sensor from STMicro + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); + if (cTemp[0] == 0x68) // WHO_AM_I + return DEVICE_LSM9DS1; + + // Check for LPS25H pressure sensor from STMicro + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); + if (cTemp[0] == 0xbd) // WHO_AM_I + return DEVICE_LPS25H; + + // Check for HTS221 temp/humidity sensor from STMicro + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); + if (cTemp[0] == 0xbc) // WHO_AM_I + return DEVICE_HTS221; + + // Check for MAG3110 + I2CReadRegister(pI2C, i, 0x07, cTemp, 1); + if (cTemp[0] == 0xc4) // WHO_AM_I + return DEVICE_MAG3110; + + // Check for LM8330 keyboard controller + I2CReadRegister(pI2C, i, 0x80, cTemp, 2); + if (cTemp[0] == 0x0 && cTemp[1] == 0x84) // manufacturer code + software revision + return DEVICE_LM8330; + + // Check for MAX44009 + if (i == 0x4a || i == 0x4b) + { + for (j=0; j<8; j++) + I2CReadRegister(pI2C, i, j, &cTemp[j], 1); // check for power-up reset state of registers + if ((cTemp[2] == 3 || cTemp[2] == 2) && cTemp[6] == 0 && cTemp[7] == 0xff) + return DEVICE_MAX44009; + } + + // Check for ADS1115 + I2CReadRegister(pI2C, i, 0x02, cTemp, 2); // Lo_thresh defaults to 0x8000 + I2CReadRegister(pI2C, i, 0x03, &cTemp[2], 2); // Hi_thresh defaults to 0x7fff + if (cTemp[0] == 0x80 && cTemp[1] == 0x00 && cTemp[2] == 0x7f && cTemp[3] == 0xff) + return DEVICE_ADS1115; + + // Check for MCP9808 + I2CReadRegister(pI2C, i, 0x06, cTemp, 2); // manufacturer ID && get device ID/revision + I2CReadRegister(pI2C, i, 0x07, &cTemp[2], 2); // need to read them individually + if (cTemp[0] == 0 && cTemp[1] == 0x54 && cTemp[2] == 0x04 && cTemp[3] == 0x00) + return DEVICE_MCP9808; + + // Check for BMP280/BME280 + I2CReadRegister(pI2C, i, 0xd0, cTemp, 1); + if (cTemp[0] == 0x55) // BMP180 + return DEVICE_BMP180; + else if (cTemp[0] == 0x58) + return DEVICE_BMP280; + else if (cTemp[0] == 0x60) // BME280 + return DEVICE_BME280; + + // Check for LSM6DS3 + I2CReadRegister(pI2C, i, 0x0f, cTemp, 1); // WHO_AM_I + if (cTemp[0] == 0x69) + return DEVICE_LSM6DS3; + + // Check for ADXL345 + I2CReadRegister(pI2C, i, 0x00, cTemp, 1); // DEVID + if (cTemp[0] == 0xe5) + return DEVICE_ADXL345; + + // Check for MPU-60x0i, MPU-688x, and MPU-9250 + I2CReadRegister(pI2C, i, 0x75, cTemp, 1); + if (cTemp[0] == (i & 0xfe)) // Current I2C address (low bit set to 0) + return DEVICE_MPU6000; + else if (cTemp[0] == 0x71) + return DEVICE_MPU9250; + else if (cTemp[0] == 0x19) + return DEVICE_MPU6886; + + // Check for DS3231 RTC + I2CReadRegister(pI2C, i, 0x0e, cTemp, 1); // read the control register + if (i == 0x68 && cTemp[0] == 0x1c) // fixed I2C address and power on reset value + return DEVICE_DS3231; + } + return iDevice; +} /* I2CDiscoverDevice() */ \ No newline at end of file diff --git a/include_sensor_libraries.h b/include_sensor_libraries.h new file mode 100644 index 0000000..2772e3f --- /dev/null +++ b/include_sensor_libraries.h @@ -0,0 +1,58 @@ +#include // https:github.com/MajenkoLibraries/Average + + +#include +#include //https://github.com/arcao/Syslog.git +#include +#include // https://github.com/bblanchon/ArduinoStreamUtils.git + + +#include + +#include + +#include // https://github.com/ +#include // https://github.com/ +#include // https://github.com/ +#include // https://github.com/avaldebe/PMserial +#include // https://github.com/adafruit/Adafruit_VEML6070 +#include // https://github.com/adafruit/Adafruit_PCF8591 +#include // https://github.com/adafruit/Adafruit_INA219 +#include // https://github.com/adafruit/Adafruit_MPU6050 +#include // https://github.com/adafruit/Adafruit_Sensor +#include // https://github.com/adafruit/Adafruit_APDS9960 +#include // https://github.com/adafruit/Adafruit_SHT31 +#include // https://github.com/adafruit/Adafruit_BMP280 +#include // https://github.com/adafruit/Adafruit_CCS811 +#include // https://github.com/adafruit/Adafruit_BMP085 +#include // https://github.com/claws/BH1750 +#include // https://github.com/ +#include // https://github.com/QuentinCG/Arduino-LM75A-Temperature-Sensor-Library +#include // https://github.com/adafruit/Adafruit_HTU21DF_Library +#include // https://github.com/ + +// #include //inlude the library +// +// +[env:esp32doit-devkit-v1] +platform = espressif32 +board = esp32doit-devkit-v1 +framework = arduino +lib_deps = + avaldebe/PMSerial@^1.2.0 + https://github.com/adafruit/Adafruit_INA219 + https://github.com/adafruit/Adafruit_MPU6050 + https://github.com/avaldebe/PMserial + https://github.com/adafruit/Adafruit_VEML6070 + https://github.com/adafruit/Adafruit_PCF8591 + https://github.com/adafruit/Adafruit_INA219 + https://github.com/adafruit/Adafruit_Sensor + https://github.com/adafruit/Adafruit_APDS9960 + https://github.com/adafruit/Adafruit_SHT31 + https://github.com/adafruit/Adafruit_BMP280 + https://github.com/adafruit/Adafruit_CCS811 + ; https://github.com/adafruit/Adafruit_HTU21DF_Library + ; https://github.com/RobTillaart/SHT2x + https://github.com/enjoyneering/HTU21D + https://github.com/claws/BH1750 +lib_extra_dirs = /Users/alverson/projects/microcontrollers/dev/libraries diff --git a/io_utils.h b/io_utils.h index 134d0b7..33fb876 100644 --- a/io_utils.h +++ b/io_utils.h @@ -1,6 +1,15 @@ #ifndef io_utils_h #define io_utils_h +#include +#include + +#ifdef ESP32 +// #include // ERROPiX/ESP32_AnalogWrite +#endif + +bool swap = false; + int getPinMode(uint8_t pin) { if (pin >= NUM_DIGITAL_PINS) return (-1); @@ -15,20 +24,32 @@ int getPinMode(uint8_t pin) } void debugPin(uint8_t pin){ - Serial.print("[PIN] " + (String)pin); - Serial.print(" pinmode: "); - Serial.print(getPinMode(pin),HEX); - Serial.println(" pinstate: " + (String)digitalRead(pin)); + Logger.print("[PIN] " + (String)pin); + Logger.print(" pinmode: "); + Logger.print(getPinMode(pin),HEX); + Logger.println(" pinstate: " + (String)digitalRead(pin)); } -void scani2c(){ + + +// i2c scanner +// @todo add oled support, remember device addrs and lookup indexes, +// detect new device, shows list of devices when it gets to your device press button or unplug device , +// it will then be stored and automatically setup. + + +// #include + +uint16_t scani2c(bool pinswap = false){ + swap = pinswap; byte error, address; int nDevices; - Wire.begin(); - Serial.print("[I2C] SDA:"+(String) SDA); - Serial.print(" SCL:"+(String) SCL); - Serial.println(""); - Serial.println("[I2C] Scanning ... "); + if(!swap) Wire.begin(); + else Wire.begin(SCL,SDA); // begin(sda, scl) SWAP! + Logger.print("[I2C] SDA:"+(String) SDA); + Logger.print(" SCL:"+(String) SCL); + Logger.println(swap ? " \nSWAPPED" : ""); + Logger.println("[I2C] Scanning ... "); nDevices = 0; for(address = 1; address < 127; address++ ) @@ -39,80 +60,157 @@ void scani2c(){ Wire.beginTransmission(address); int res = Wire.endTransmission(); - // * Output 0 .. success - // * 1 .. length to long for buffer - // * 2 .. address send, NACK received - // * 3 .. data send, NACK received - // * 4 .. other twi error (lost bus arbitration, bus error, ..) - + // https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/ + // endTransmission() returns: + // 0: success. + // 1: data too long to fit in transmit buffer. + // 2: received NACK on transmit of address. + // 3: received NACK on transmit of data. + // 4: other error. + // 5: timeout + if (res == 0) { - Serial.print("[I2C] Device found - ADDR: 0x"); - if (address<16) - Serial.print("0"); - Serial.print(address,HEX); - Serial.println(""); + Logger.print("[I2C] Device found - ADDR: 0x"); + if (address<16)Logger.print("0x"); + Logger.print(address,HEX); // 7 bit + Logger.print(" 0x"); + Logger.print(2*address,HEX); // 8bit + Logger.println(); + nDevices++; } - else if(res!=2) - { - Serial.println("[ERROR]:" + (String)res); - Serial.print("Unknown error ADDR: 0x"); - if (address<16) - Serial.print("0"); - Serial.print(address,HEX); - Serial.println(""); + else if(res!=2 && res !=255){ + Logger.print("[ERROR]: code: " + (String)res); + Logger.print(" ADDR: 0x"); + if (address<16) Logger.print("0x"); + Logger.print(address,HEX); // 7 bit + Logger.print(" 0x"); + Logger.print(2*address,HEX); // 8bit + Logger.println(); + } } if (nDevices == 0) - Serial.println("[ERROR] No I2C devices found\n"); - else - Serial.println("[I2C] scan done\n"); + Logger.println("[ERROR] No I2C devices found\n"); + else{ + Logger.print("[I2C] scan done found "); + Logger.println(nDevices); + } + + return nDevices; } void scanPins(){ for(int i = 0;i<6;i++){ if(i == 1) continue; pinMode(i,INPUT_PULLUP); - Serial.print((String)digitalRead(i)); + Logger.print((String)digitalRead(i)); // debugPin(i); } for(int i = 12;i<17;i++){ pinMode(i,INPUT_PULLUP); // debugPin(i); - Serial.print((String)digitalRead(i)); + Logger.print((String)digitalRead(i)); } - Serial.println(""); + Logger.println(""); } -#ifdef ESP32 -// ADC2 restoring procedure -// This is a Workaround to use ADC2 Pins on ESP32 when Wifi or Bluetooth is on. -// (usually only ADC1 Pins are usable for analogRead() when Wifi or Bluetooth is on.) -// -- We save the ADC2 control register before WifiBegin() or BluetoothBegin() -// -- then restore its original value, then set a specific bit of the ADC2 control register -//to avoid inverted readings: we do the latter two before every analogRead() cycle. -// -- This achieves ADC2 usability even when Wifi/Bluetooth are turned on! - -#include "esp32-hal-adc.h" // needed for adc pin reset -#include "soc/sens_reg.h" // needed for manipulating ADC2 control register -uint64_t reg_b; // Used to store ADC2 control register -int value; - -void storeADC() { -// Save ADC2 control register value : Do this before begin Wifi/Bluetooth -reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG); -// Wifi.Begin(); // or similar wifi init function or Bluetooth begin() +void pinregister(){ + // maintain a store of pins we are using before passing them to functions + // better than a simple define, as we can + // register a pin for use, to avoid using a pin twice + // even if this is a preocompiler structure, it would stil be able to warn + // also can let you set the use as a flag so you know if you are using it as adc or input + // and on esp32 etc set the pins desired specs and avoid conflicts with multiple adc reads } -void restoreADC() { -// ADC2 control register restoring -WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, reg_b); -//VERY IMPORTANT: DO THIS TO NOT HAVE INVERTED VALUES! -SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); -Serial.println(analogRead(4)); -Serial.println(analogRead(33)); -} -#endif + +// The ADC firmware driver API supports ADC1 (8 channels, attached to GPIOs 32 – 39), +// and ADC2 (10 channels, attached to GPIOs 0, 2, 4, 12 – 15, and 25 – 27). +// However, the usage of ADC2 has some restrictions for the application: + +// ADC2 is used by the Wi-Fi driver. Therefore the application can only use ADC2 when the Wi-Fi driver has not been started. +// Some of the ADC2 pins are used as strapping pins (GPIO 0, 2, 15) thus cannot be used freely. + +// #ifdef ESP32 + +// #define ADC_1 36 +// #define ADC_2 38 // missing from some boards? +// #define ADC_3 39 +// #define ADC_4 32 +// #define ADC_5 33 +// #define ADC_6 34 +// #define ADC_7 37 + +// // ADC2 restoring procedure +// // This is a Workaround to use ADC2 Pins on ESP32 when Wifi or Bluetooth is on. +// // (usually only ADC1 Pins are usable for analogRead() when Wifi or Bluetooth is on.) +// // -- We save the ADC2 control register before WifiBegin() or BluetoothBegin() +// // -- then restore its original value, then set a specific bit of the ADC2 control register +// //to avoid inverted readings: we do the latter two before every analogRead() cycle. +// // -- This achieves ADC2 usability even when Wifi/Bluetooth are turned on! + +// #include "esp32-hal-adc.h" // needed for adc pin reset +// #include "soc/sens_reg.h" // needed for manipulating ADC2 control register +// uint64_t reg_b; // Used to store ADC2 control register +// int value; + +// void storeADC() { +// // Save ADC2 control register value : Do this before begin Wifi/Bluetooth +// reg_b = READ_PERI_REG(SENS_SAR_READ_CTRL2_REG); +// // Wifi.Begin(); // or similar wifi init function or Bluetooth begin() +// } + +// void restoreADC() { +// // ADC2 control register restoring +// WRITE_PERI_REG(SENS_SAR_READ_CTRL2_REG, reg_b); +// //VERY IMPORTANT: DO THIS TO NOT HAVE INVERTED VALUES! +// SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV); +// Logger.println(analogRead(4)); +// Logger.println(analogRead(33)); +// } +// #endif + + +// //ISR test +// struct Button { +// const uint8_t PIN; +// uint32_t numberKeyPresses; +// bool pressed; +// }; + +// Button button1 = {36, 0, false}; +// Button button2 = {32, 0, false}; + +// void isr_begin(){ +// pinMode(button1.PIN, INPUT_PULLUP); +// attachInterruptArg(button1.PIN, isr, &button1, FALLING); +// pinMode(button2.PIN, INPUT_PULLUP); +// attachInterrupt(button2.PIN, isr, FALLING); +// } + +// void IRAM_ATTR isr_test_a(void* arg) { +// Button* s = static_cast(arg); +// s->numberKeyPresses += 1; +// s->pressed = true; +// } + +// void IRAM_ATTR isr_test_b() { +// button2.numberKeyPresses += 1; +// button2.pressed = true; +// } + +// void process_isr_test(){ +// if (button1.pressed) { +// Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses); +// button1.pressed = false; +// } +// // Serial.print(digitalRead(ENC_PINA)); +// // Serial.print(digitalRead(ENC_PINB)); +// // Serial.print(digitalRead(ENC_SW)); +// // Serial.println(" <- ENC"); +// } + #endif \ No newline at end of file diff --git a/json.h b/json.h new file mode 100644 index 0000000..9d2b943 --- /dev/null +++ b/json.h @@ -0,0 +1,46 @@ +#ifndef json_h +#define json_h + +#include + + +void json_test(){ + char json[] = + "{\"sensor\":\"gps\",\"time\":1351824120,\"data\":[48.756080,2.302038]}"; + + // Deserialize the JSON document + DeserializationError error = deserializeJson(doc, json); + // deserializeJson(doc, STREAM); + + // Test if parsing succeeds. + if (error) { + Serial.print(F("deserializeJson() failed: ")); + Serial.println(error.f_str()); + return; + } + + serializeJsonPretty(json, Serial); + + const char* sensor = doc["sensor"]; + long time = doc["time"]; + double latitude = doc["data"][0]; + double longitude = doc["data"][1]; + + // Print values. + Serial.println(sensor); + Serial.println(time); + Serial.println(latitude, 6); + Serial.println(longitude, 6); + + // The filter: it contains "true" for each value we want to keep + // StaticJsonDocument<200> filter; + // filter["list"][0]["dt"] = true; + // filter["list"][0]["main"]["temp"] = true; + + // // Deserialize the document + // StaticJsonDocument<400> doc; + // deserializeJson(doc, input_json, DeserializationOption::Filter(filter)); + +} + +#endif \ No newline at end of file diff --git a/jsontest.h b/jsontest.h new file mode 100644 index 0000000..e77d6c9 --- /dev/null +++ b/jsontest.h @@ -0,0 +1,62 @@ +#include + +StaticJsonDocument<1024> payload; +StaticJsonDocument<1024> rootdoc; +DynamicJsonDocument pubjson(1024); +JsonArray jsondata = pubjson.to(); + +void setup(){ + Serial.begin(115200); +} + +void add(){ + payload["topic"] = "thetopic"; + payload["clientid"] = "theclientid"; + payload["type"] = "thetype"; + payload["value"] = "thevalue"; + jsondata.add(payload); +} + +void prepare(){ + rootdoc.add(pubjson); + + char message[1024]; + serializeJson(rootdoc, message); + Serial.println((String)message); + // client.publish(topic,message); // do stuff + + // serial output, arrlen is 3 last element is always null + // [{"topic":"thetopic","clientid":"theclientid","type":"thetype","value":"thevalue"}, + // {"topic":"thetopic","clientid":"theclientid","type":"thetype","value":"thevalue"},null] + + // clean + rootdoc.clear(); + jsondata = pubjson.to(); +} + +void test(){ + StaticJsonDocument<256> doc; + + JsonObject doc_0 = doc.createNestedObject(); + doc_0["topic"] = "device"; + doc_0["clientid"] = "ESP_ENV"; + doc_0["type"] = "uptime_s"; + doc_0["value"] = 25; + + JsonObject doc_1 = doc.createNestedObject(); + doc_1["topic"] = "device"; + doc_1["clientid"] = "ESP_ENV"; + doc_1["type"] = "rssi"; + doc_1["value"] = 92; + + serializeJson(doc, Serial); +} + + +void loop(){ + add(); + add(); + prepare(); + // test(); + delay(5000); +} \ No newline at end of file diff --git a/lcd_i2c.h b/lcd_i2c.h index bbc4e48..10f460a 100755 --- a/lcd_i2c.h +++ b/lcd_i2c.h @@ -1,413 +1,418 @@ -// #include <../LiquidCrystal_I2C/LiquidCrystal_I2C.h> - -const int numRows = 2; -const int numCols = 16; -int backlightState = true; - -uint8_t _SCL = 15; -uint8_t _SDA = 13; - -// i2c pins nodemcu -// SCL D1 -// SDA D2 -LiquidCrystal_I2C lcd(0x27,numCols,numRows); // set the LCD address to 0x27 for a 16 chars and 2 line display - -// quality icon 0-6 0x - 100% -/* - * XXXXX - * X X - * X - * X X - * XXX - * XXXXX - * XXXXXX - */ -byte qualityIco[][8] = { -{ - 0b11100, - 0b10100, - 0b01000, - 0b01000, - 0b00000, - 0b10100, - 0b01000, - 0b10100 -}, -{ - 0b11100, - 0b10100, - 0b01000, - 0b01000, - 0b00000, - 0b00000, - 0b00000, - 0b10000 -}, -{ - 0b11100, - 0b10100, - 0b01000, - 0b01000, - 0b00000, - 0b00000, - 0b01000, - 0b11000 -}, -{ - 0b11100, - 0b10100, - 0b01000, - 0b01000, - 0b00000, - 0b00100, - 0b01100, - 0b11100 -}, -{ - 0b11100, - 0b10100, - 0b01000, - 0b01000, - 0b00010, - 0b00110, - 0b01110, - 0b11110 -}, -{ - 0b11100, - 0b10100, - 0b01000, - 0b01001, - 0b00011, - 0b00111, - 0b01111, - 0b11111 -} -}; - - - -byte block4[4][8] = { -{ - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111 -} -}; - -byte block[8][8] = { -{ - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111, - 0b11111 -}, -{ - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b00000, - 0b11111 -} -}; - -// degrees F -byte degF[8] = { - 0b01000, - 0b10100, - 0b01000, - 0b00000, - 0b00011, - 0b00100, - 0b00111, - 0b00100 -}; - -// dergees C -byte degC[8] = { - 0b01000, - 0b10100, - 0b01000, - 0b00000, - 0b00011, - 0b00100, - 0b00100, - 0b00011 -}; - -// thermometer -byte thermico[8] = { - 0b00100, - 0b01010, - 0b01010, - 0b01110, - 0b01110, - 0b11111, - 0b11111, - 0b01110 -}; - -// droplet -byte humico[8] = { - 0b00100, - 0b00100, - 0b01010, - 0b01010, - 0b10001, - 0b10001, - 0b10001, - 0b01110 -}; - -// small % -byte perc[8] = { - 0b00000, - 0b00000, - 0b10010, - 0b00100, - 0b01000, - 0b10010, - 0b00000, - 0b00000 -}; - -byte arial[8] = { - 0b11111, - 0b10101, - 0b01110, - 0b00100, - 0b00100, - 0b00100, - 0b00100, - 0b00000 -}; - -byte wifi[8] = { - 0b01110, - 0b10001, - 0b00100, - 0b01010, - 0b00000, - 0b00100, - 0b00000, - 0b00000 -}; - -byte db[8] = { - 0b00000, - 0b00000, - 0b11100, - 0b00000, - 0b00110, - 0b11111, - 0b10101, - 0b11111 -}; - -byte link[4][8] = { -{ - 0b00000, - 0b00111, - 0b11101, - 0b10111, - 0b10000, - 0b10101, - 0b11010, - 0b00101 -}, -{ - 0b00000, - 0b00111, - 0b11101, - 0b10111, - 0b10000, - 0b10111, - 0b11101, - 0b00111 -}, -{ - 0b11100, - 0b10111, - 0b11101, - 0b00000, - 0b00000, - 0b11101, - 0b10111, - 0b11100 -}, -{ - 0b10100, - 0b01011, - 0b10101, - 0b00001, - 0b00001, - 0b11101, - 0b10111, - 0b11100 -} -}; - - -const uint8_t WIFIQICO = 0; -const uint8_t ARIALICO = 1; -const uint8_t WIFIDBICO = 32; // space -const uint8_t WIFILINKICO = 2; // space -const uint8_t GRAPHICO = 2; - -// dynamic icon -uint8_t getQualityIcon(int rssi){ - if(rssi >=0 || rssi<-96) rssi = 0; // -96 unusable signal, +int invalid rssi - else rssi = map(rssi,-1,-100,5,1); - Serial.println("quality: " + (String)rssi); - lcd.createChar(0,qualityIco[rssi]); - return 0; -} -// dynamic icon -uint8_t getConnectIcon(int connState){ - return 32; - // Serial.println("connect: " + (String)connState); - lcd.createChar(WIFILINKICO,link[connState]); - return WIFILINKICO; -} - -void initLcdChars(){ - lcd.createChar(WIFIQICO, qualityIco[0]); - lcd.createChar(ARIALICO, arial); - lcd.createChar(WIFILINKICO, link[0]); - lcd.createChar(WIFIDBICO, db); -} - -uint8_t getGraphIcon(int in){ - int value = map(in,100,0,GRAPHICO,GRAPHICO+5); - if(value == GRAPHICO) return 255; // 0 - return value; -} - -void initLcdGraphChars(){ - // lcd.createChar(GRAPHICO, block[1]); // char 255 - lcd.createChar(GRAPHICO+1, block[2]); - lcd.createChar(GRAPHICO+2, block[3]); - lcd.createChar(GRAPHICO+3, block[4]); - lcd.createChar(GRAPHICO+4, block[5]); - lcd.createChar(GRAPHICO+5, block[6]); - // lcd.createChar(range+6, block[3]); -} - -void initLCD(){ - Wire.setClock(400000L); // set i2c speed 400khz - Wire.begin(_SDA,_SCL); - lcd.init(); // initialize the lcd - - if(backlightState) lcd.backlight(); - else lcd.noBacklight(); - - lcd.clear(); - delay(500); - lcd.print("Booting......"); - - // create a new custom character - initLcdChars(); - initLcdGraphChars(); +#include + +const int numRows = 2; +const int numCols = 16; +int backlightState = true; + +uint8_t _SCL = 15; +uint8_t _SDA = 13; + +// i2c pins nodemcu +// SCL D1 +// SDA D2 +LiquidCrystal_I2C lcd(0x27,numCols,numRows); // set the LCD address to 0x27 for a 16 chars and 2 line display + +// quality icon 0-6 0x - 100% +/* + * XXXXX + * X X + * X + * X X + * XXX + * XXXXX + * XXXXXX + */ +byte qualityIco[][8] = { +{ + 0b11100, + 0b10100, + 0b01000, + 0b01000, + 0b00000, + 0b10100, + 0b01000, + 0b10100 +}, +{ + 0b11100, + 0b10100, + 0b01000, + 0b01000, + 0b00000, + 0b00000, + 0b00000, + 0b10000 +}, +{ + 0b11100, + 0b10100, + 0b01000, + 0b01000, + 0b00000, + 0b00000, + 0b01000, + 0b11000 +}, +{ + 0b11100, + 0b10100, + 0b01000, + 0b01000, + 0b00000, + 0b00100, + 0b01100, + 0b11100 +}, +{ + 0b11100, + 0b10100, + 0b01000, + 0b01000, + 0b00010, + 0b00110, + 0b01110, + 0b11110 +}, +{ + 0b11100, + 0b10100, + 0b01000, + 0b01001, + 0b00011, + 0b00111, + 0b01111, + 0b11111 +} +}; + + + +byte block4[4][8] = { +{ + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111 +} +}; + +byte block[8][8] = { +{ + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111, + 0b11111 +}, +{ + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b00000, + 0b11111 +} +}; + +// degrees F +byte degF[8] = { + 0b01000, + 0b10100, + 0b01000, + 0b00000, + 0b00011, + 0b00100, + 0b00111, + 0b00100 +}; + +// dergees C +byte degC[8] = { + 0b01000, + 0b10100, + 0b01000, + 0b00000, + 0b00011, + 0b00100, + 0b00100, + 0b00011 +}; + +// thermometer +byte thermico[8] = { + 0b00100, + 0b01010, + 0b01010, + 0b01110, + 0b01110, + 0b11111, + 0b11111, + 0b01110 +}; + +// droplet +byte humico[8] = { + 0b00100, + 0b00100, + 0b01010, + 0b01010, + 0b10001, + 0b10001, + 0b10001, + 0b01110 +}; + +// small % +byte perc[8] = { + 0b00000, + 0b00000, + 0b10010, + 0b00100, + 0b01000, + 0b10010, + 0b00000, + 0b00000 +}; + +byte arial[8] = { + 0b11111, + 0b10101, + 0b01110, + 0b00100, + 0b00100, + 0b00100, + 0b00100, + 0b00000 +}; + +byte wifi[8] = { + 0b01110, + 0b10001, + 0b00100, + 0b01010, + 0b00000, + 0b00100, + 0b00000, + 0b00000 +}; + +byte db[8] = { + 0b00000, + 0b00000, + 0b11100, + 0b00000, + 0b00110, + 0b11111, + 0b10101, + 0b11111 +}; + +byte wlink[4][8] = { +{ + 0b00000, + 0b00111, + 0b11101, + 0b10111, + 0b10000, + 0b10101, + 0b11010, + 0b00101 +}, +{ + 0b00000, + 0b00111, + 0b11101, + 0b10111, + 0b10000, + 0b10111, + 0b11101, + 0b00111 +}, +{ + 0b11100, + 0b10111, + 0b11101, + 0b00000, + 0b00000, + 0b11101, + 0b10111, + 0b11100 +}, +{ + 0b10100, + 0b01011, + 0b10101, + 0b00001, + 0b00001, + 0b11101, + 0b10111, + 0b11100 +} +}; + + +const uint8_t WIFIQICO = 0; +const uint8_t ARIALICO = 1; +const uint8_t WIFIDBICO = 32; // space +const uint8_t WIFILINKICO = 2; // space +const uint8_t GRAPHICO = 2; + +// dynamic icon +uint8_t getQualityIcon(int rssi){ + if(rssi >=0 || rssi<-96) rssi = 0; // -96 unusable signal, +int invalid rssi + else rssi = map(rssi,-1,-100,5,1); + Serial.println("quality: " + (String)rssi); + lcd.createChar(0,qualityIco[rssi]); + return 0; +} +// dynamic icon +uint8_t getConnectIcon(int connState){ + return 32; + // Serial.println("connect: " + (String)connState); + lcd.createChar(WIFILINKICO,wlink[connState]); + return WIFILINKICO; +} + +void initLcdChars(){ + lcd.createChar(WIFIQICO, qualityIco[0]); + lcd.createChar(ARIALICO, arial); + lcd.createChar(WIFILINKICO, wlink[0]); + lcd.createChar(WIFIDBICO, db); +} + +uint8_t getGraphIcon(int in){ + int value = map(in,100,0,GRAPHICO,GRAPHICO+5); + if(value == GRAPHICO) return 255; // 0 + return value; +} + +void initLcdGraphChars(){ + // lcd.createChar(GRAPHICO, block[1]); // char 255 + lcd.createChar(GRAPHICO+1, block[2]); + lcd.createChar(GRAPHICO+2, block[3]); + lcd.createChar(GRAPHICO+3, block[4]); + lcd.createChar(GRAPHICO+4, block[5]); + lcd.createChar(GRAPHICO+5, block[6]); + // lcd.createChar(range+6, block[3]); +} + +void initLCD(){ + // Wire.begin(_SDA,_SCL); + Wire.begin(); + Wire.setClock(1700000L); // set i2c speed 400khz + lcd.init(); // initialize the lcd + + lcd.noBacklight(); + delay(1000); + lcd.backlight(); + + if(backlightState) lcd.backlight(); + else lcd.noBacklight(); + + lcd.clear(); + delay(500); + lcd.print("Booting......"); + + // create a new custom character + initLcdChars(); + initLcdGraphChars(); } \ No newline at end of file diff --git a/led_funcs.h b/led_funcs.h index c005117..9e343e5 100755 --- a/led_funcs.h +++ b/led_funcs.h @@ -1,14 +1,14 @@ -/** - * LED STUFF - */ - -// #include <../bit_bang_neopixel_binary/bit_bang_neopixel_binary.h> -#include -#include <../bit_bang_neopixel_binary/custom_color_funcs.h> - -// #ifdef ESP8266 -// #ifdef NEOHIGHSPEED -// // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution -// extern "C" void ICACHE_RAM_ATTR espShow( -// uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); +/** + * LED STUFF + */ + +// #include <../bit_bang_neopixel_binary/bit_bang_neopixel_binary.h> +#include +#include <../bit_bang_neopixel_binary/custom_color_funcs.h> + +// #ifdef ESP8266 +// #ifdef NEOHIGHSPEED +// // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution +// extern "C" void ICACHE_RAM_ATTR espShow( +// uint8_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); // #endif \ No newline at end of file diff --git a/log.h b/log.h index ad29016..8cfb4d0 100644 --- a/log.h +++ b/log.h @@ -1,6 +1,151 @@ #ifndef log_h #define log_h +/** + * Local logging solutions, using steamutils and syslog + * StreamUtils + * https://github.com/Chris--A/PrintEx + * Allows for stream buffering, redirection, mirroring etc. + * + * syslog + * https://github.com/arcao/Syslog.git + * An Arduino library for logging to Syslog server via `UDP` protocol in + * [IETF (RFC 5424)] and [BSD (RFC 3164)] message format + */ + +#define USESYSLOG + +#ifdef USESYSLOG +#include +#include +#endif + +/** + * syslog preparer + * @todo, streamutils should have buffering capabilities already, replace our buffer + * @param msg [description] + */ + +char logbuffer[256]; +int logbufferidx = 0; // end char +// might need a ring buffer here, so we can keep logging mutiple messages and send delayed +bool syslogactive = true; + +void sendToSyslog(String msg){ + #ifdef USESYSLOG + // if(logData.indexOf("\n") >= 0){ + // Serial.println("newline found at: " + (String)logData.indexOf("\n")); + // syslog.log(LOG_INFO,msg); + // } + // Serial.print("[RAW] "); + // Serial.println(String(logbuffer).substring(0,logbufferidx)); + + // Log to buffer, do string matching for LOG LEVEL + msg = String(logbuffer).substring(0,logbufferidx-2); + String msgb = msg; + msgb.toLowerCase(); // lowercase for string match levels + msgb.trim(); // remove cr lf + + uint16_t level = LOG_INFO; + if(msgb.indexOf("notice") != -1) level = LOG_NOTICE; + if(msgb.indexOf("error") != -1) level = LOG_ERR; + if(msgb.indexOf("warning") != -1) level = LOG_WARNING; + if(msgb.indexOf("fatal") != -1) level = LOG_CRIT; + if(syslogactive) syslog.log(level,msg); // SEND IT + // if(syslogactive) syslog.log(level,(String)millis()+" "+msg); + // @todo clean up string, remove whitespace such as CR LF \t + + // reset buffer + logbuffer[0] = (char)0; + logbufferidx = 0; + #endif +} + + +/** + * setup logger stream wrapper, redirection + */ +class print2syslog : public Stream { +public: + bool begun = true; // allow muting via availability + virtual int available() { return (begun); } + virtual int read() { return (0); } + virtual int peek() { return (0); } + virtual void flush() {} + void begin(unsigned long, uint8_t) {begun = true;} + void end() {begun=false;} + + virtual size_t write(uint8_t newchar) { + if(!begun) return 0; + logbuffer[logbufferidx] = newchar; + logbufferidx++; + if(logbufferidx>256 || newchar == 0x0a) sendToSyslog(""); // buffer full or newline, @todo if no newline at max buffer drop it, use flag for delayed write + return (1); + } + + virtual size_t write(const uint8_t *buffer, size_t size) + { + if(!begun) return 0; + size_t n = 0; + while(size--) { + n += write(*buffer++); + } + return n; + } +}; + +print2syslog syslogger; +// syslogger.begin(); + +/** + * Setup streamutils stream redirection/mirroring + * @todo abstract into init class + * + * This library provides some helper classes and functions for dealing with streams. + * For example, with this library, you can: + * speed of your program by buffering the data it reads from a file + * reduce the number of packets sent over WiFi by buffering the data you send + * improve the reliability of a serial connection by adding error correction codes + * debug your program more easily by logging what it sends to a Web service + * send large data with the [Wire library](https://www.arduino.cc/en/reference/wire) + * use a `String` or EEPROM with a stream interface + * + * Logger + + * |-> syslogger -> syslog UDP netlog + * |-> Serial -> (uart/usbserial) + */ +#include + +Stream &_Logger = Serial; +LoggingStream Logger(syslogger, _Logger); +// Stream &Logger = Serial; // BYPASS lOGGER + +// #ifdef USESYSLOG +// LoggingStream Logger(syslogger, _Logger); +// #else + // Stream &Logger = Serial; // BYPASS lOGGER +// #endif + +// logging streams options +// String result = LoggingStream.str(); +// WriteLoggingStream loggingClient(client, Serial); +// loggingClient.println("GET / HTTP/1.1"); +// loggingClient.println("User-Agent: Arduino"); + + +/** + * Basic Debug logging methods + * DEBUGGER(debuglevel_t LOG_LEVEL,F(msg)); + * DEBUGGER(debuglevel_t LOG_LEVEL,F(msg),value); // for msg value pairs + * + * #DEBUG_LEVEL + * #DEBUG_PORT + * + * PREFIX:[LOGLEVEL] msg + * MAX will output timestamps and memory info + */ + + #include #ifdef ESP8266 @@ -37,35 +182,35 @@ #endif template - void DEBUG_WM(Generic text); + void DEBUGGER(Generic text); template - void DEBUG_WM(debuglevel_t level,Generic text); + void DEBUGGER(debuglevel_t level,Generic text); template - void DEBUG_WM(Generic text,Genericb textb); + void DEBUGGER(Generic text,Genericb textb); template - void DEBUG_WM(debuglevel_t level, Generic text,Genericb textb); + void DEBUGGER(debuglevel_t level, Generic text,Genericb textb); // DEBUG -// @todo fix DEBUG_WM(0,0); +// @todo fix DEBUGGER(0,0); template -void DEBUG_WM(Generic text) { - DEBUG_WM(DEBUG_NOTIFY,text,""); +void DEBUGGER(Generic text) { + DEBUGGER(DEBUG_NOTIFY,text,""); } template -void DEBUG_WM(debuglevel_t level,Generic text) { - if(_debugLevel >= level) DEBUG_WM(level,text,""); +void DEBUGGER(debuglevel_t level,Generic text) { + if(_debugLevel >= level) DEBUGGER(level,text,""); } template -void DEBUG_WM(Generic text,Genericb textb) { - DEBUG_WM(DEBUG_NOTIFY,text,textb); +void DEBUGGER(Generic text,Genericb textb) { + DEBUGGER(DEBUG_NOTIFY,text,textb); } template -void DEBUG_WM(debuglevel_t level,Generic text,Genericb textb) { +void DEBUGGER(debuglevel_t level,Generic text,Genericb textb) { if(!_debug || _debugLevel < level) return; if(_debugLevel >= DEBUG_MAX){ @@ -91,7 +236,7 @@ void DEBUG_WM(debuglevel_t level,Generic text,Genericb textb) { _debugPort.printf("[MEM] free: %5d | max: %5d | frag: %3d%% \n", free, max, frag); #endif } - _debugPort.print("*WM: "); + _debugPort.print("*DLOG: "); if(_debugLevel == DEBUG_DEV) _debugPort.print("["+(String)level+"] "); _debugPort.print(text); if(textb){ @@ -110,14 +255,15 @@ void DEBUG_WM(debuglevel_t level,Generic text,Genericb textb) { void debugPlatformInfo(){ #ifdef ESP8266 system_print_meminfo(); - DEBUG_WM(F("getCoreVersion(): "),ESP.getCoreVersion()); - DEBUG_WM(F("system_get_sdk_version(): "),system_get_sdk_version()); - DEBUG_WM(F("system_get_boot_version():"),system_get_boot_version()); - DEBUG_WM(F("getFreeHeap(): "),(String)ESP.getFreeHeap()); + DEBUGGER(F("getCoreVersion(): "),ESP.getCoreVersion()); + DEBUGGER(F("system_get_sdk_version(): "),system_get_sdk_version()); + DEBUGGER(F("system_get_boot_version():"),system_get_boot_version()); + DEBUGGER(F("getFreeHeap(): "),(String)ESP.getFreeHeap()); #elif defined(ESP32) size_t freeHeap = heap_caps_get_free_size(MALLOC_CAP_8BIT); - DEBUG_WM("Free heap: ", freeHeap); - DEBUG_WM("ESP-IDF version: ", esp_get_idf_version()); + DEBUGGER("Free heap: ", freeHeap); + DEBUGGER("ESP-IDF version: ", esp_get_idf_version()); + // log_v("Chip Info: Model: %d, cores: %d, revision: %d", chipInfo.model, chipInfo.cores, chipInfo.revision); #endif } diff --git a/log_syslog.h b/log_syslog.h new file mode 100644 index 0000000..1b13400 --- /dev/null +++ b/log_syslog.h @@ -0,0 +1,154 @@ +#ifndef log_syslog_h +#define log_syslog_h + +#include +#include +#include +#include +#include + +WiFiUDP udpClient; + +Syslog syslog(udpClient, SYSLOG_PROTO_IETF); // SYSLOG_PROTO_BSD +// Syslog syslog(udpClient, SYSLOG_SERVER, SYSLOG_PORT, DEVICE_HOSTNAME, APP_NAME, LOG_KERN); + +String logTopic = "ESP"; +int iteration = 1; + +#define DEVICE_HOSTNAME "unknown-device" +#define APP_NAME "unkown-app" + +const char* syslog_hostname; +const char* syslog_appname; + +bool debug_syslog = true; +bool syslog_begun = false; + +// Setup netlog logging +void init_syslog(const char* hostname){ + + if(debug_syslog){ + Serial.println("[LOG] syslog init"); + Serial.println("[LOG] syslog devicehostname: " + (String)syslog_hostname); + Serial.println("[LOG] syslog appname: " + logTopic); + } + + syslog_hostname = hostname; + syslog_appname = logTopic.c_str(); + // prepare syslog configuration here + // (can be anywhere before first call of log/logf method) + syslog.server(syslog_server_ip, syslog_server_port); + syslog.deviceHostname(syslog_hostname); + syslog.appName(syslog_appname); + syslog.defaultPriority(LOG_INFO); // default log level if none +} + +// bool log(uint16_t pri, const String &message); +// bool log(uint16_t pri, const char *message); +bool sendSysLog(uint16_t level, const String &msg){ + if(!syslog_begun) return false; + return syslog.log(level,msg); +} + +bool sendSysLog(uint16_t level, const char *msg){ + if(!syslog_begun) return false; + return syslog.log(level,msg); +} + +// tester +void sendLogTest(){ + if(!syslog_begun) return; + String startmsg = "[LOG] SYSLOG TEST"; + syslog.log(LOG_INFO, startmsg); + return; + // Log message can be formated like with printf function. + syslog.logf(LOG_ERR, "This is error message no. %d", iteration); + syslog.logf(LOG_INFO, "This is info message no. %d", iteration); + + // You can force set facility in pri parameter for this log message. More + // facilities in syslog.h or in Linux syslog documentation. + syslog.logf(LOG_DAEMON | LOG_INFO, "This is daemon info message no. %d", iteration); + + // You can set default facility and severity level and use it for all log + // messages (beware defaultPriority is stored permanently!) + // syslog.defaultPriority(LOG_FTP | LOG_INFO); + syslog.logf("This is ftp info message no. %d", iteration); + + // Send log messages up to LOG_WARNING severity + syslog.logMask(LOG_UPTO(LOG_WARNING)); + syslog.log(LOG_ERR, "This is logged."); + syslog.log(LOG_WARNING, "This is logged."); + syslog.log(LOG_NOTICE, "This is not logged."); + syslog.log(LOG_INFO, "This is not logged."); + + // F() macro is supported too + syslog.log(LOG_INFO, F("End loop")); + iteration++; +} + +// // Syslog protocol format +// #define SYSLOG_PROTO_IETF 0 // RFC 5424 +// #define SYSLOG_PROTO_BSD 1 // RFC 3164 + +// /* +// * priorities/facilities are encoded into a single 32-bit quantity, where the +// * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility +// * (0-big number). Both the priorities and the facilities map roughly +// * one-to-one to strings in the syslogd(8) source code. This mapping is +// * included in this file. +// * +// * priorities (these are ordered) +// */ +// #define LOG_EMERG 0 /* system is unusable */ +// #define LOG_ALERT 1 /* action must be taken immediately */ +// #define LOG_CRIT 2 /* critical conditions */ +// #define LOG_ERR 3 /* error conditions */ +// #define LOG_WARNING 4 /* warning conditions */ +// #define LOG_NOTICE 5 /* normal but significant condition */ +// #define LOG_INFO 6 /* informational */ +// #define LOG_DEBUG 7 /* debug-level messages */ + +// #define LOG_PRIMASK 0x07 /* mask to extract priority part (internal) */ +// /* extract priority */ +// #define LOG_PRI(p) ((p) & LOG_PRIMASK) +// #define LOG_MAKEPRI(fac, pri) (((fac) << 3) | (pri)) + +// /* facility codes */ +// #define LOG_KERN (0<<3) kernel messages +// #define LOG_USER (1<<3) /* random user-level messages */ +// #define LOG_MAIL (2<<3) /* mail system */ +// #define LOG_DAEMON (3<<3) /* system daemons */ +// #define LOG_AUTH (4<<3) /* security/authorization messages */ +// #define LOG_SYSLOG (5<<3) /* messages generated internally by syslogd */ +// #define LOG_LPR (6<<3) /* line printer subsystem */ +// #define LOG_NEWS (7<<3) /* network news subsystem */ +// #define LOG_UUCP (8<<3) /* UUCP subsystem */ +// #define LOG_CRON (9<<3) /* clock daemon */ +// #define LOG_AUTHPRIV (10<<3) /* security/authorization messages (private) */ +// #define LOG_FTP (11<<3) /* ftp daemon */ + +// /* other codes through 15 reserved for system use */ +// #define LOG_LOCAL0 (16<<3) /* reserved for local use */ +// #define LOG_LOCAL1 (17<<3) /* reserved for local use */ +// #define LOG_LOCAL2 (18<<3) /* reserved for local use */ +// #define LOG_LOCAL3 (19<<3) /* reserved for local use */ +// #define LOG_LOCAL4 (20<<3) /* reserved for local use */ +// #define LOG_LOCAL5 (21<<3) /* reserved for local use */ +// #define LOG_LOCAL6 (22<<3) /* reserved for local use */ +// #define LOG_LOCAL7 (23<<3) /* reserved for local use */ +// +// System errors +// Example of a system error message: + +// May 11 10:40:48 scrooge disk-health-nurse[26783]: [ID 702911 user.error] m:SY-mon-full-500 c:H : partition health measures for /var did not suffice - still using 96% of partition space + +// The message can be split in to the following columns: + +// Column 1 = "May 11 10:40:48" > Timestamp +// Column 2 = "scrooge" > Loghost +// Column 3 = "disk-health-nurse[26783]:" > Application/Process +// Column 4 = "[ID 702911 user.error]" > Syslog facility.level +// Column 5 = "m:SY-mon-full-500" > Message ID +// Column 6 = "c:H : partition health..." > Message [possibly including rid, sid, ip] + +#endif \ No newline at end of file diff --git a/max31855.h b/max31855.h index 87b3bf2..891aae3 100644 --- a/max31855.h +++ b/max31855.h @@ -1,14 +1,7 @@ #ifndef max31855_h #define max31855_h -// #include "MAX31855.h" // by Rob Tillaart Library Manager (NO HSPI!!) -#include "Adafruit_MAX31855.h" // Seperate calls for spiread for each function, no raw bit cache! -#include -// #include // @todo test quickstats, add child class for container -// #include // https://github.com/provideyourown/statistics -#include -#include -#include +#define DEBUG // NODEMCU hspi // HW scl D5 14 @@ -17,16 +10,35 @@ // HW cs D8 15 // #define MAXDO 5 // HWMISO -#define MAXCS 16 // 2 -#define MAXCLK 14 // HWSLK -#define MAXMISO 4 -Adafruit_MAX31855 tc(MAXCLK,MAXCS,MAXMISO); +// #define MAXCS 15 // 2 +// #define MAXCLK 14 // HWSLK +// #define MAXMISO 13 + +#define USE_max6675 + +#ifdef USE_max6675 +#include "max6675.h" + +MAX6675 tc(MAX_SCK,MAX_CS,MAX_SDO); +#else +// #include "MAX31855.h" // by Rob Tillaart Library Manager (NO HSPI!!) +#include "Adafruit_MAX31855.h" // Seperate calls for spiread for each function, no raw bit cache! +Adafruit_MAX31855 tc(MAX_SCK,MAX_CS,MAX_SDO); +#endif + +#include +// #include // @todo test quickstats, add child class for container +// #include // https://github.com/provideyourown/statistics +#include +#include + +// Adafruit_MAX31855 tc(14,15,12); #ifdef TC2 Adafruit_MAX31855 tcB(1); #endif -bool updateLock = false; +bool updateLock = false; // lockout updating temps // Averaging // options @@ -66,7 +78,7 @@ float internalTemp = 0; // cold junction float currentTempCorr = 0; // linearized k type float lastTemp = -1; // used in pid.h -int TCinterval = 200; // temp reading interval +int TCinterval = 0; // temp reading interval // TC WARN // options @@ -108,11 +120,27 @@ float correctKType(){ currentTempCorr = correctedCelsius(tcmv,internalTemp); } +float readInternal(){ + #ifdef USE_max6675 + return 0; + #else + return tc.readInternal(); + #endif +} + +uint8_t readError(){ + #ifdef USE_max6675 + return 0; + #else + return tc.readError(); + #endif +} + // @todo better average library, lerp etc void ReadCurrentTempAvg() { - int status = tc.readError(); - float internal = tc.readInternal(); + int status = readError(); + float internal = readInternal(); if(useInternal) currentTempAvg += internal + tempOffset; else currentTempAvg += tc.readCelsius() + tempOffset; avgReadCount++; @@ -130,14 +158,14 @@ void ReadCurrentTempAvg() // Read the temp probe void ReadCurrentTemp() { - lastTCStatus = tc.readError(); + lastTCStatus = readError(); #ifdef DEBUG // Serial.print("tc status: "); // Serial.println( status ); #endif if(useInternal){ // use internal cj as real temp, useful for testing without tc or monitoring pcb etc - internalTemp = tc.readInternal(); + internalTemp = readInternal(); currentTemp = internalTemp + tempOffset; } else { @@ -206,8 +234,8 @@ void updateDevVars(){ } void updateAltTemps(){ - internalTemp = tc.readInternal(); - lastTCStatus = tc.readError(); + internalTemp = readInternal(); + lastTCStatus = readError(); } @@ -221,7 +249,7 @@ void updateTemps(){ // if(updateLock) return; // digitalWrite(0,LOW); // fixes DC left HIGH and data clocked to max ic causing screen artifacts. delay(TCinterval); // stabilizes temperatures ???? - internalTemp = tc.readInternal(); + internalTemp = readInternal(); ReadCurrentTemp(); if(!useAveraging)updateDevVars(); // Serial.println(currentTemp); @@ -311,17 +339,22 @@ else tft.setTextColor( YELLOW, BLACK ); void initTC(){ // Start up the MAX31855 - bool res = tc.begin(); + bool res; + #ifdef USE_max6675 + res = true; + #else + res = tc.begin(); + #endif // if(!res) add check now, see commits delay(200); - tc.readError(); + readError(); // check for sanity Serial.println("[TC] MAX31855 Thermocouple Begin..."); if(!TCSanityCheck()) Serial.println("[ERROR] Status: "+ getTcStatus()); #ifdef DEBUG printTC(); - // Serial.println("[TC] "+(String)round(tc.readInternal())); + // Serial.println("[TC] "+(String)round(readInternal())); // Serial.println("[TC] "+(String)round(tc.readCelsius())); // Serial.println("[TC] "+(String)round(readFahrenheit())); #endif diff --git a/mqtt.h b/mqtt.h new file mode 100644 index 0000000..3b6139e --- /dev/null +++ b/mqtt.h @@ -0,0 +1,354 @@ +#ifndef mqtt_h +#define mqtt_h + +#undef nullptr + +#define USEJSON +#ifdef USEJSON +#include // bblanchon/ArduinoJson + +// #define _JSONSIZE 4096 + +#ifndef _JSONSIZE +#define _JSONSIZE 1024 +#endif + +StaticJsonDocument<_JSONSIZE> payload; +StaticJsonDocument<_JSONSIZE> rootdoc; +// payload["sensor"] = "gps"; +// payload["time"] = 1351824120; + + // const size_t CAPACITY = JSON_ARRAY_SIZE(1); + // StaticJsonDocument docH; + // JsonArray arrayH = docH.to(); + DynamicJsonDocument pubjson(_JSONSIZE); + JsonArray jsondata = pubjson.to(); +#endif + +#include // knolleary/pubsubclient +#define MQTT_MAX_PACKET_SIZE 2048 + +WiFiClient espClient; + +PubSubClient client(espClient); + +bool debug_mqtt = true; +bool debug_mqtt_json = false; +const char* clientID = ""; + +bool mqttconnected = false; + +long lastReconnectAttempt = 0; +uint32_t mqttretry = 5000; + +void MQTTGetErrorMessage(){ +// Possible values for client.state() +// #define MQTT_CONNECTION_TIMEOUT -4 +// #define MQTT_CONNECTION_LOST -3 +// #define MQTT_CONNECT_FAILED -2 +// #define MQTT_DISCONNECTED -1 +// #define MQTT_CONNECTED 0 +// #define MQTT_CONNECT_BAD_PROTOCOL 1 +// #define MQTT_CONNECT_BAD_CLIENT_ID 2 +// #define MQTT_CONNECT_UNAVAILABLE 3 +// #define MQTT_CONNECT_BAD_CREDENTIALS 4 +// #define MQTT_CONNECT_UNAUTHORIZED 5 +} + +void MQTTreconnect() { + if (!client.connected()) { + // while (!client.connected()) { + if(debug_mqtt) Logger.println("[MQTT] Connecting..."); + // Attempt to connect + if (client.connect(clientID)) { + mqttconnected = true; + Logger.println("[MQTT] Connected"); + // Once connected, publish an announcement... + client.publish("TESTOUT", "hello world"); + // ... and resubscribe + client.subscribe("ESP_env_c/CMD"); + } else { + Logger.print("[ERROR] [MQTT] failed, rc="); // @todo we get here but no actual reconnnect + Logger.println(client.state()); + } + } +} + +void MQTTcallback(char* topic, byte* payload, unsigned int length) { + Logger.print("[MQTT] IN Message arrived ["); + Logger.print(topic); + Logger.print("] "); + Logger.print("payload: "); + for (int i = 0; i < length; i++) { + Logger.print((char)payload[i]); + } + Logger.println(""); + // RESTART + if ((char)payload[0] == '1') { + Logger.println("[MQTT] payload: 1 TRIGGERED"); + ESP.restart(); + } + // WIFI off + if ((char)payload[0] == '2') { + Logger.println("[MQTT] payload: 2 TRIGGERED"); + WiFi.disconnect(); + } +} + +boolean mqttWiFiReconnect() { + WiFi.reconnect(); + return WiFi.status() == 'WL_CONNECTED'; +} + +void mqtt_checkconn(){ + if (!client.connected()) { + long now = millis(); + if (now - lastReconnectAttempt > mqttretry) { + Logger.println("[MQTT] try client re-connect"); + lastReconnectAttempt = now; + MQTTreconnect(); + } + } else { + // Client connected + client.loop(); + } +} + +bool process_MQTT_nb(){ + if (!client.connected()) { + mqttconnected = false; + mqtt_checkconn(); + } + client.loop(); // will wait loop reconnect to mqtt + return client.connected(); +} + +bool process_MQTT(){ + if(!wifiIsConnected()){ + // Logger.println("[MQTT] wifi not connected"); + return false; + } + if(!client.connected()){ + mqttconnected = false; + Logger.print("[MQTT] client not connected => "); + Logger.println(client.state()); + MQTTreconnect(); // @todo throttle + return false; + } + client.loop(); // will wait loop reconnect to mqtt + return true; +} + +void init_MQTT(){ + if(!wifiIsConnected()) return; + if(clientID == ""){ + Logger.println("[MQTT] clientID not set"); + // clientID = getHostname(); + } + client.setServer(mqtt_server_ip, mqtt_server_port); + + // MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds. Override with setSocketTimeout() + client.setSocketTimeout(30); // #define MQTT_SOCKET_TIMEOUT 15 + // MQTT_KEEPALIVE : keepAlive interval in Seconds. Override with setKeepAlive() + client.setKeepAlive(10); // #define MQTT_KEEPALIVE 15 + + client.setCallback(MQTTcallback); + if (client.connect(clientID)){ + mqttconnected = true; + Logger.println("[MQTT] connected to " + (String)mqtt_server_ip + " as " + clientID); + } + else Logger.println("[MQTT] init failed to connect to " + (String)mqtt_server_ip); + client.setBufferSize(_JSONSIZE); + // client.subscribe("CMD"); + // client.subscribe("ESP_env_c/CMD"); + process_MQTT(); + // jsondata = pubjson.to(); + // jsondata = pubjson.createNestedArray(); +} + +void init_MQTT(const char* clientid){ + clientID = clientid; // global + init_MQTT(); +} + +void init_MQTT(const String& clientid){ + clientID = clientid.c_str(); // global + init_MQTT(); +} + +#ifdef USEJSON + +void MQTT_pub(String topic, String sensor, String value){ + if(!wifiIsConnected()){ + // Logger.print("[MQTT] OFFLINE: "); + // return; + } + if(!mqttconnected)return; + if(debug_mqtt){ + Logger.print("[MQTT] Publish: "); + Logger.print(sensor); + Logger.print(" "); + Logger.println(value); + } + if(value == "") { + // Logger.println("[ERROR] MQTT value is empty"); + return; + } + // JsonArray data = payload.createNestedArray(topic); + payload["topic"] = topic; + payload["clientid"] = clientID; + payload["type"] = sensor; + payload["value"] = value.toFloat(); + // payload["unit"] = ""; + // if(topic == "device") + jsondata.add(payload); + + // serializeJson(jsondata, Serial); + // if(debug_mqtt) serializeJson(payload, Serial); + // serializeJsonPretty(payload, Serial); + + // String output; + // serializeJson(payload,output); + // client.publish(topic.c_str(),("["+output+"\n]").c_str()); // must be object? + // close ? +} + +void MQTT_pub(String topic, String sensor, String value, bool json){ + if(!mqttconnected)return; + if(debug_mqtt){ + Logger.print("[MQTT] Publish: "); + Logger.print(sensor); + Logger.print(" "); + Logger.println(value); + } + if(value == "") { + // Logger.println("[ERROR] MQTT value is empty"); + return; + } + JsonArray data = payload.createNestedArray(topic); + payload["topic"] = data; // tag key = tag value + payload["clientid"] = clientID; + payload["type"] = sensor; // field key = field value + payload["value"] = value.toFloat(); + // payload["unit"] = ""; + // if(debug_mqtt_json) serializeJson(payload, Logger); + // serializeJsonPretty(payload, Serial); + + String output; + serializeJson(payload,output); + + client.publish(topic.c_str(),("["+output+"\n]").c_str()); // must be object? + // close ? + // mqttClient.beginMessage(topic); + // serializeJson(doc, mqttClient); + // mqttClient.endMessage(); + // client.print + // client.endPublish(); + // client.beginPublish("greenBottles/lyrics", msgLen, false); + + // const size_t capacity = JSON_ARRAY_SIZE(2) + JSON_OBJECT_SIZE(3); + // DynamicJsonBuffer jsonBuffer(capacity); + + // JsonObject& root = jsonBuffer.createObject(); + // root["sensor"] = "gps"; + // root["time"] = 1351824120; + + // JsonArray& data = root.createNestedArray("data"); + // data.add(48.75608); + // data.add(2.302038); + + // root.printTo(Serial); +} + +void MQTT_pub_send(String topic){ + if(!mqttconnected)return; + if(debug_mqtt){ + Logger.println("[MQTT] sending json for topic: " + topic); + } + // serializeJson(jsondata, Logger); + // rootdoc.createNestedObject(); + // rootdoc.add(pubjson); + // String output; + // serializeJson(pubjson,output); + // Serial.println(output); + // serializeJson(rootdoc,output); + // Serial.println(output); + // Serial.flush(); + + char message[_JSONSIZE]; + serializeJson(pubjson, message); + if(debug_mqtt_json){ + Logger.println((String)message); + Logger.flush(); + } + client.publish(topic.c_str(),message); + delay(500); + // pubjson.clear(); + rootdoc.clear(); + // jsondata.clear(); + // rootdoc.createNestedObject(jsondata); + jsondata = pubjson.to(); + // payload.clear(); + // pubjson.garbageCollect(); +} + +#else +void MQTT_pub(String topic, String msg){ + if(!mqttconnected)return; + Logger.print("[MQTT] Publish message: "); + Logger.print("topic: "); + Logger.print(topic); + Logger.print(" mesg: "); + Logger.println(msg); + client.publish(topic.c_str(), msg.c_str()); +} + +void MQTT_pub(String topic, String sensor, String value){ + if(!mqttconnected)return; + Logger.print("[MQTT] Publish message: "); + Logger.print("topic: "); + Logger.print(topic+"/"+clientID+"/"+sensor); + Logger.print("\t\tvalue: "); + Logger.println(value); + if(value == "") { + Logger.println("[ERROR] MQTT value is empty"); + return; + } + client.publish((topic+"/"+clientID+"/"+sensor).c_str(), value.c_str()); +} +#endif + + +#ifdef ESP8266 + #define ESP_getChipId() ESP.getChipId() +#elif defined(ESP32) + #define ESP_getChipId() (uint32_t)ESP.getEfuseMac() +#endif + +void MQTT_pub_device(bool verbose){ + if(!mqttconnected)return; + if(debug_mqtt) Logger.println("[MQTT] Publish Device"); + MQTT_pub("device","uptime_s",(String)(millis()/1000)); + MQTT_pub("device","rssi",(String)getRSSIasQuality()); + MQTT_pub("device","heap",(String)ESP.getFreeHeap()); + if(verbose){ + // MQTT_pub("device","ip",(String)ESP.getFreeHeap()); + // MQTT_pub("device","hostname",(String)ESP.getFreeHeap()); + MQTT_pub("device","ChipType",(String)ESP.getChipModel()); + MQTT_pub("device","chipID",(String)ESP_getChipId()); + MQTT_pub("device","ESPver",(String)ESP.getSdkVersion()); + MQTT_pub("device","chipCores",(String)ESP.getChipCores()); + MQTT_pub("device","chipRev",(String)ESP.getChipRevision()); + } + // MQTT_pub("device","hall",(String)hallRead()); + #ifdef ESP32 + // MQTT_pub("device","temp",(String)temperatureRead()); + #endif + MQTT_pub_send("device"); +} + +void MQTT_pub_device(){ + MQTT_pub_device(false); +} + +#endif \ No newline at end of file diff --git a/neo_ind_accent.h b/neo_ind_accent.h index 158a815..04cab2f 100644 --- a/neo_ind_accent.h +++ b/neo_ind_accent.h @@ -41,7 +41,7 @@ void rainbowAccent(int wait) { void indAccentTest(){ bool quicktest = true; - int wait = quicktest ? 5 : 50; + int wait = quicktest ? 5 : 100; ind.setBrightness(255); // full bright for(size_t i=0;i<20;i++){ diff --git a/neoindicator.h b/neoindicator.h index 0a47f22..9433cf5 100644 --- a/neoindicator.h +++ b/neoindicator.h @@ -9,8 +9,29 @@ bool DEBUG_neoind = false; bool DEBUG_neoind = false; #endif +#ifdef ESP32 +bool showTwice = true; +bool noInterrupts = false; // causes crashes, sometimes ? +#else +bool showTwice = false; +bool noInterrupts = false; +#endif + +// // these are const, so they don't eat RAM +// const uint32_t np_white = ind.Color(255,255,255); +// const uint32_t np_black = ind.Color(0 ,0,0); +// const uint32_t np_red = ind.Color(255,0,0); +// const uint32_t np_orange = ind.Color(255,128,0); +// const uint32_t np_yellow = ind.Color(255,100,0); // 255,100,0 +// const uint32_t np_green = ind.Color(0 ,255,0); +// const uint32_t np_cyan = ind.Color(0 ,255,128); +// const uint32_t np_blue = ind.Color(0 ,0,255); +// const uint32_t np_purple = ind.Color(128,0,255); +// const uint32_t np_turquoise = ind.Color(0,80,80); + #include Adafruit_NeoPixel ind = Adafruit_NeoPixel(); + // Adafruit_NeoPixel strip = Adafruit_NeoPixel(1, PIN, NEO_GRB + NEO_KHZ800); // Adafruit_NeoPixel strip *= ind; @@ -21,28 +42,38 @@ Adafruit_NeoPixel ind = Adafruit_NeoPixel(); // palevioletred #DB7093 rgb(219,112,147) // mediumvioletred #C71585 rgb(199,21,133) -uint16_t INDBRIGHTNESS = 30; -int INDNUMPIXELS = 1; +uint16_t INDBRIGHTNESS = 60; +int INDNUMPIXELS = 4; #define INDPIXELSTYPE NEO_GRB + NEO_KHZ800 bool INDPINRESET = false; uint8_t neoIndTaskID; // timer task +uint32_t indColor; // save color + void init_indicator(uint16_t pin){ // Adafruit_NeoPixel // strip = ind; + Serial.println("[NEOIND] init pin# " + (String)pin); ind.setPin(pin); - ind.setBrightness(INDBRIGHTNESS); + ind.setBrightness(100); ind.updateLength(INDNUMPIXELS); ind.updateType(NEO_GRB + NEO_KHZ800); ind.begin(); ind.show(); ind.show(); // on purpose, ensure its blanked for glitched resets delay(1); - if(INDPINRESET) digitalWrite(ind.getPin(),HIGH); // reset // init_strip(); } +/** + * [indSetNextColor description] + * @param c [description] + */ +void indSetNextColor(uint32_t c){ + indColor = c; +} + void debugColor(uint32_t c){ Serial.println("Debug color"); Serial.println("[RGB] Red: " + (String)red(c)); @@ -50,18 +81,46 @@ void debugColor(uint32_t c){ Serial.println("[RGB] Blue: " + (String)blue(c)); } +void indSetColorB(uint32_t c){ + if(DEBUG_neoind)Serial.println("[IND] set ind color:" + (String)c); + // debugColor(c); + ind.setPixelColor( 1, c); + if(INDPINRESET) digitalWrite(ind.getPin(),HIGH); // reset + #ifdef ESP32 + if(noInterrupts) portDISABLE_INTERRUPTS(); + #endif + ind.show(); + if(showTwice) ind.show(); + #ifdef ESP32 + if(noInterrupts) portENABLE_INTERRUPTS(); + #endif + // #endif +} + void indSetColor(uint32_t c){ if(DEBUG_neoind)Serial.println("[IND] set ind color:" + (String)c); // debugColor(c); - ind.setPixelColor( 0, c ); + uint32_t color = ColorRGBA(red(c),green(c),blue(c),INDBRIGHTNESS); + // ind.setPixelColor( 0, color ); + ind.fill(color); + if(INDPINRESET) digitalWrite(ind.getPin(),HIGH); // reset + #ifdef ESP32 + if(noInterrupts) portDISABLE_INTERRUPTS(); + #endif ind.show(); - if(INDPINRESET) digitalWrite(ind.getPin(),HIGH); // reset + if(showTwice) ind.show(); + #ifdef ESP32 + if(noInterrupts) portENABLE_INTERRUPTS(); + #endif + // #endif + indSetNextColor(ind.getPixelColor(0)); } // alias void setIndBrightness(uint16_t alpha = INDBRIGHTNESS){ - ind.setBrightness(alpha); + INDBRIGHTNESS = alpha; + // ind.setBrightness(alpha); } void setIndColor(uint32_t c){ @@ -71,12 +130,20 @@ void setIndColor(uint32_t c){ void indSetColor(uint8_t r,uint8_t g,uint8_t b){ if(DEBUG_neoind)Serial.println("[IND] set ind color RGB:"+(String) ind.Color(r,g,b)); // debugColor(ind.Color(r,g,b)); - ind.setPixelColor(0,ind.Color(r,g,b)); - ind.show(); - // delay(1); - if(INDPINRESET) digitalWrite(ind.getPin(),HIGH); // reset + indSetColor(ind.Color(r,g,b)); } +// void setPixelBrightness(uint32_t n, uint32_t a){ +// } + +// void indSetBrightness(uint8_t a){ +// uint32_t c = strip.getPixelColor(0); +// // if(DEBUG_neoind)Serial.println("[IND] set ind color brightness:"+(String) ind.Color(r,g,b)); +// setPixelColorAlpha(n,c,a); +// ind.setPixelBrightness +// } + + void setIndColor(uint8_t r,uint8_t g,uint8_t b){ indSetColor(r,g,b); } @@ -90,6 +157,14 @@ void stop_indicator(){ // @todo unset object } +// non blocking stepped color setter +void updateIndColor(){ + if(indColor != ind.getPixelColor(0)){ + ind.setPixelColor(0,indColor); + ind.show(); + } +} + // Rainbow cycle along whole strip. Pass delay time (in ms) between frames. void rainbowInd(int wait) { // Hue of first pixel runs 3 complete loops through the color wheel. @@ -119,8 +194,8 @@ void rainbowInd(int wait) { // Input a value 0 to 255 to get a color value. // The colours are a transition r - g - b - back to r. uint32_t indWheel(byte WheelPos) { - Serial.print("indWheel: "); - Serial.print(WheelPos,BIN); + // Serial.print("indWheel: "); + // Serial.print(WheelPos,BIN); WheelPos = 255 - WheelPos; if(WheelPos < 85) { return ind.Color(255 - WheelPos * 3, 0, WheelPos * 3); @@ -162,17 +237,17 @@ void indClear(){ } } -void indTest(){ - bool quicktest = true; - int wait = quicktest ? 1 : 50; +void indTest(bool quicktest = true){ + // bool quicktest = true; + int wait = quicktest ? 1 : 100; ind.setBrightness(255); // full bright indSetColor(255,0,0); - delay(500); + delay(wait*100); indSetColor(0,255,0); - delay(500); + delay(wait*100); indSetColor(0,0,255); - delay(500); + delay(wait*100); indSetColor(0,0,0); delay(200); @@ -184,10 +259,17 @@ void indTest(){ rainbowInd(wait); indSetColor(0,0,0); // set black - ind.setBrightness(INDBRIGHTNESS); // set normal brightness + // ind.setBrightness(INDBRIGHTNESS); // set normal brightness Serial.println("[IND] indtest complete"); } +void indTest2(){ + ind.setBrightness(255); // full bright + + indSetColor(255,0,0); + delay(500); +} + void accentSetColor(uint32_t c){ if(DEBUG_neoind)Serial.println("[IND] set accent color"); for(size_t i=1; i IND_ANIMDELAY) IND_nb_rainbow(); } + +void processNeoInd(){ + updateIndColor(); +} + #endif \ No newline at end of file diff --git a/neopixel_helper.h b/neopixel_helper.h index 3233a27..0fa617f 100644 --- a/neopixel_helper.h +++ b/neopixel_helper.h @@ -1,3 +1,7 @@ +/** + * All helpers need to be refactored to use neopixel objected passed in + * kludge reassign strip to your obj etc and use as a shadow + */ #ifndef NEOPIXEL_HELPER_H #define NEOPIXEL_HELPER_H @@ -8,8 +12,8 @@ bool DEBUG_neohelp = false; #endif uint16_t NEOBRIGHTNESS = 100; -int NEONUMPIXELS = 1; -#define NEOPIXELSTYPE NEO_GRB + NEO_KHZ800 +int NEONUMPIXELS = 5; +#define NEOPIXELSTYPE NEO_RGB + NEO_KHZ800 #include // Adafruit_NeoPixel strip = Adafruit_NeoPixel(); @@ -17,26 +21,38 @@ int NEONUMPIXELS = 1; Adafruit_NeoPixel strip = Adafruit_NeoPixel(); // these are const, so they don't eat RAM -const uint32_t np_white = strip.Color(255,255,255); -const uint32_t np_black = strip.Color(0 ,0,0); -const uint32_t np_red = strip.Color(255,0,0); -const uint32_t np_orange = strip.Color(255,128,0); -const uint32_t np_yellow = strip.Color(255,100,0); // 255,100,0 -const uint32_t np_green = strip.Color(0 ,255,0); -const uint32_t np_cyan = strip.Color(0 ,255,128); -const uint32_t np_blue = strip.Color(0 ,0,255); -const uint32_t np_purple = strip.Color(128,0,255); -const uint32_t np_turquoise = strip.Color(0,80,80); - +const uint32_t np_white = strip.Color(255, 255, 255); +const uint32_t np_black = strip.Color( 0, 0, 0); +const uint32_t np_red = strip.Color(255, 0, 0); +const uint32_t np_orange = strip.Color(255, 128, 0); +const uint32_t np_yellow = strip.Color(255, 100, 0); // 255,100,0 +const uint32_t np_green = strip.Color( 0, 255, 0); +const uint32_t np_cyan = strip.Color( 0, 255, 128); +const uint32_t np_blue = strip.Color( 0, 0, 255); +const uint32_t np_purple = strip.Color(128, 0, 255); +const uint32_t np_pink = strip.Color(128, 0, 255); +const uint32_t np_turquoise = strip.Color( 0, 80, 80); + + // pink #FFC0CB rgb(255,192,203) + // lightpink #FFB6C1 rgb(255,182,193) + // hotpink #FF69B4 rgb(255,105,180) + // deeppink #FF1493 rgb(255,20,147) + // palevioletred #DB7093 rgb(219,112,147) + // mediumvioletred #C71585 rgb(199,21,133) + // /** * collection of helper functions */ +void init_strip(int pin, Adafruit_NeoPixel& ind){ + strip = ind; return; +} + void init_strip(int pin){ strip.setPin(pin); strip.setBrightness(NEOBRIGHTNESS); strip.updateLength(NEONUMPIXELS); - strip.updateType(NEO_GRB + NEO_KHZ800); + strip.updateType(NEOPIXELSTYPE); strip.begin(); strip.show(); strip.show(); // on purpose, ensure its blanked for glitched resets @@ -95,6 +111,7 @@ uint32_t Wheel(byte WheelPos) { uint8_t getRGBA(uint8_t rgb, uint16_t A){ if(A > 255 || rgb == 0) return rgb; if(A < 255) return floor(A*rgb/255); + return rgb; } // RGB to binary with MAXBRIGHTNESS brightness scaling @@ -149,6 +166,7 @@ uint16_t randomBrightness(uint16_t a,uint8_t range){ return b; } +// does not allow offsets 0-255 uint16_t getBrightnessStep(uint8_t step, uint16_t numsteps){ uint16_t brightness; // brightness = 255 - (step * (255/numsteps)); // linear @@ -293,6 +311,7 @@ void fadeTo(uint32_t c,uint16_t duration){ fade(getPixelColor(0),c,duration); } +// stepping non blocking fader uint32_t getFadeStep(uint32_t startColor, uint32_t endColor, uint16_t steps, uint16_t step){ int16_t redDiff = red(endColor) - red(startColor); int16_t greenDiff = green(endColor) - green(startColor); @@ -305,7 +324,8 @@ uint32_t getFadeStep(uint32_t startColor, uint32_t endColor, uint16_t steps, uin blueValue = (int16_t)blue(startColor) + (blueDiff * step / steps); whiteValue = (int16_t)white(startColor) + (whiteDiff * step / steps); - return color(redValue, greenValue, blueValue,whiteValue); + // return color(redValue, greenValue, blueValue,whiteValue); + return color(redValue, greenValue, blueValue); } void flasher(uint32_t colorA, uint32_t colorB,int waitA, int waitB){ @@ -327,7 +347,7 @@ void flasherSmooth(uint32_t colorA, uint32_t colorB,int waitA, int waitB){ } unsigned long NEO_lastUpdate = 0 ; // for millis() when last update occoured -uint32_t NEO_ANIMDELAY = 60; +uint32_t NEO_ANIMDELAY = 10; void NEO_nb_rainbow() { // modified from Adafruit example to make it a state machine static uint16_t neo_j=128; @@ -345,6 +365,60 @@ void NEO_nb_animate(){ if(millis() - NEO_lastUpdate > NEO_ANIMDELAY) NEO_nb_rainbow(); } +void rainbow(int wait) { + // Hue of first pixel runs 3 complete loops through the color wheel. + // Color wheel has a range of 65536 but it's OK if we roll over, so + // just count from 0 to 3*65536. Adding 256 to firstPixelHue each time + // means we'll make 3*65536/256 = 768 passes through this outer loop: + for(long firstPixelHue = 0; firstPixelHue < 3*65536; firstPixelHue += 256) { + // for(int i=0; i + +void setup(){ + +} + +void loop(){ + printNTC(); + calc_ntc(get_PCF8591(0)*16); + calc_ntc_B(get_PCF8591(1)*16); + calc_ntc_C(get_PCF8591(2)*16); + calc_ntc_D(get_PCF8591(3)*16); + Serial.println(String(get_ntc()/10)); + Serial.println(String(get_ntc_B()/10)); + Serial.println(String(get_ntc_C()/10)); + Serial.println(String(get_ntc_D()/10)); +} \ No newline at end of file diff --git a/number_format.h b/number_format.h index 81c8ea0..dc4fdfb 100644 --- a/number_format.h +++ b/number_format.h @@ -9,4 +9,21 @@ float round_f_2(float x){ return round(x); } +// inline double round( double val ) +// { +// if( val < 0 ) return ceil(val - 0.5); +// return floor(val + 0.5); +// } + +// template +// string sFormat(const char *f, T value) +// { +// char buffer[64]; +// snprintf(buffer, sizeof(buffer), f, value); +// return string(buffer); +// } + +// printf("When this number: %f is assigned to 2 dp, it will be: %.2f ", 94.9456, 94.9456); + + #endif \ No newline at end of file diff --git a/oled_i2c.h b/oled_i2c.h index 4d6c80a..812bd6b 100644 --- a/oled_i2c.h +++ b/oled_i2c.h @@ -1,22 +1,23 @@ /*oled_i2c*/ +#ifndef oled_i2c_h +#define oled_i2c_h #include +#include #include #include // #define SH1106_128_64 -#define SCREEN_WIDTH 128 // OLED display width, in pixels -#define SCREEN_HEIGHT 64 // OLED display height, in pixels +#define SCREEN_WIDTH 32 // OLED display width, in pixels +#define SCREEN_HEIGHT 128 // OLED display height, in pixels #define OLED_RESET -1 // Adafruit_SSD1306 lcd(OLED_RESET); +// Adafruit_SSD1306 lcd(SCREEN_WIDTH, SCREEN_HEIGHT); Adafruit_SSD1306 lcd(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET,800000,800000); -int fpsmicros = 0; - -// #if (SSD1306_LCDHEIGHT != 64) -// #error("Height incorrect, please fix Adafruit_SSD1306.h!"); -// #endif +int oledfpsmicros = 0; +int fontlineheight = 9; void invertText(){ lcd.setTextColor(BLACK, WHITE); // 'inverted' text @@ -26,6 +27,10 @@ void whiteText(){ lcd.setTextColor(WHITE); // 'inverted' text } +void i2cpinswap(){ + Wire.begin(SCL,SDA); // begin(sda, scl) SWAP! +} + // void init_oled(){ // init_oled(false); // } @@ -50,20 +55,35 @@ void print_oled(String str,uint8_t size,bool flush){ lcd.setTextColor(WHITE); lcd.setCursor(0,0); lcd.println(str); - if(flush)lcd.display(); + if(flush) lcd.display(); } -void init_oled(bool preamble){ +/** + * print oled lines + * @param str string to print + * @param no line 0-3 + * @param size text size 1-2 + */ +void print_oled_line(String str,uint16_t no = 1,uint16_t size = 1){ + uint16_t y = 0; + if(size == 1) y = fontlineheight*no; + if(size == 2) y = (fontlineheight*2)*no; + lcd.setCursor(0,y); + lcd.setTextSize(size); + lcd.println(str); +} + +void init_oled(bool preamble = true){ Serial.println("\nInitializing SSD1306 OLED"); Serial.println("SDA: "+(String)SDA); Serial.println("SCL: "+(String)SCL); - Wire.begin(SCL,SDA); // begin(sda, scl) SWAP! + // Wire.begin(SCL,SDA); // begin(sda, scl) SWAP! // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally if(!lcd.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 Serial.println(F("SSD1306 allocation failed")); } - + // lcd.setRotation(2); // Wire.setClock(400000L); // set i2c speed 400khz // Wire.setClock(100000L); // set i2c speed 400khz @@ -77,15 +97,42 @@ void init_oled(bool preamble){ lcd.setTextSize(1); lcd.setCursor(0,0); - lcd.println("Booting...."); + lcd.println("Booting...."); // show init lcd.display(); delay(1000); - lcd.clearDisplay(); + lcd.clearDisplay(); // clear display lcd.display(); } +void oled_test(uint8_t num = 1){ + // print_oled_line(msg, line, size); + for(uint8_t i=0;i #include // #include // #include @@ -16,6 +19,121 @@ #include #endif +// Wire.begin(SDA,SCL); +// Wire.setClock(400000L); + +// const char WIFI_SYMBOL[] = { 93,94,123,168, 176, 247, 253, 263, 277,278,279,280,281, '\0'}; +#define GLYPH_BELL 93 // bell +#define GLYPH_BT 94 // bt +#define GLYPH_CLOCK 123 // clock +#define GLYPH_FLAME 168 // flame +#define GLYPH_CHART 176 // chart +#define GLYPH_SIGNAL 253 // bell +#define GLYPH_SPARK 96 // bell +#define GLYPH_GEAR 129 // bell +#define GLYPH_ALERT 0x118 // bell +#define GLYPH_SPKOFF 0x117 // bell +#define GLYPH_SPKHI 0x115 // bell +#define GLYPH_SPKLO 0x116 // bell +#define GLYPH_HASHF 177 // bell +#define GLYPH_HASHM 178 // bell +#define GLYPH_HASHC 179 // bell +#define GLYPH_HDOTS 155 // bell +#define GLYPH_HBAR 221 // bell +#define GLYPH_CROSS 218 // bell +#define GLYPH_CROSSB 234 // bell +#define GLYPH_EKG 238 // bell +#define GLYPH_WIFI 0x119 // bell +#define GLYPH_WRENCH 0x120 // bell +#define GLYPH_TARGET 0x107 // bell +#define GLYPH_LISTINV 0x101 // bell +#define GLYPH_STAR 0x102 // bell +#define GLYPH_SUN 0x103 // bell +#define GLYPH_STPWTCH 269 // bell +#define GLYPH_TERM 0x109 // bell +#define GLYPH_DEL 0x121 // bell +#define GLYPH_GOOD 120 // bell +#define GLYPH_BAD 121 // bell +#define GLYPH_HEART 183 // bell +#define GLYPH_HOUSE 184 // bell +#define GLYPH_SQUARE 217 // bell +#define GLYPH_SPACE 287 // bell +#define GLYPH_NO 87 // busted +#define GLYPH_COFFEE 2615 // busted +#define GLYPH_TRENDUP 112 // up arrow +#define GLYPH_TRENDDN 110 // down arrow + +// const char* testing = u8"\u0263\u0BA3\u0B82"; + +// lcd.setFont(u8g2_font_open_iconic_embedded_1x_t); +// lcd.setFont(u8g2_font_open_iconic_all_1x_t); +// lcd.drawStr(0,y,WIFI_SYMBOL); +// lcd.drawUTF8(0,y,testing); +// lcd.drawGlyph(0,y, 93); // bell +// lcd.drawGlyph(10,y, 94); // bluetooth +// lcd.drawGlyph(20,y, 123); // clock +// lcd.drawGlyph(30,y, 168); // flame +// lcd.drawGlyph(40,y, 176); // chart +// lcd.drawGlyph(50,y, 253); // signal +// lcd.drawGlyph(60,y, 96); // terminus +// lcd.drawGlyph(70,y, 129); // gear +// lcd.drawGlyph(80,y, 0x118); // alert +// lcd.drawGlyph(90,y, 0x117); // speaker off +// lcd.drawGlyph(100,y, 0x115); // speaker high +// lcd.drawGlyph(110,y, 0x116); // speaker med + +// lcd.drawGlyph(0,y, 177); // hash fine +// lcd.drawGlyph(10,y, 178); // hash med +// lcd.drawGlyph(20,y, 179); // hash low +// lcd.drawGlyph(30,y, 155); // 3 dots +// lcd.drawGlyph(40,y, 221); // mid bar +// lcd.drawGlyph(50,y, 218); // cross +// lcd.drawGlyph(60,y, 234); // cross +// lcd.drawGlyph(60,y, 238); // heartbeat + +// lcd.drawGlyph(40,y,0x119); // wifi +// lcd.drawGlyph(50,y,0x120); // wrench not working +// lcd.drawGlyph(60,y,0x107); // target +// lcd.drawGlyph(70,y,0x101); // list inverted +// lcd.drawGlyph(80,y,0x102); // star +// lcd.drawGlyph(90,y,0x103); // sunshine +// lcd.drawGlyph(100,y,269); // stopwatch +// lcd.drawGlyph(110,y,0x109); // terminal +// lcd.drawGlyph(120,y,0x121); // delete +// +// +// lcd.drawGlyph(70,y, 120); // good +// lcd.drawGlyph(80,y, 121); // bad +// lcd.drawGlyph(90,y, 183); // heart +// lcd.drawGlyph(100,y, 184); // house +// lcd.drawGlyph(110,y, 217); // square +// // lcd.drawGlyph(110,y, 287); // space + +// if(glyphanimstate==0){ +// lcd.drawGlyph(120,y, 155); // +// glyphanimstate = 1; +// } +// else{ +// lcd.drawGlyph(120,y, 287); // +// glyphanimstate = 0; +// } + + +// https://github.com/olikraus/u8g2/wiki/fntlistall#24-pixel-height +// U8g2 Font names +// '_' '_' +// Description +// t Transparent font, Do not use a background color. +// h All glyphs have common height. +// m All glyphs have common height and width (monospace). +// 8 All glyphs fit into a 8x8 pixel box. +// Description +// f The font includes up to 256 glyphs. +// r Only glyphs on the range of the ASCII codes 32 to 127 are included in the font. +// u Only glyphs on the range of the ASCII codes 32 to 95 (uppercase chars) are included in the font. +// n Only numbers and extra glyphs for writing date and time strings are included in the font. +// ... Other custom character list. + // #define WHITE SH110X_WHITE // #define BLACK SH110X_BLACK @@ -30,7 +148,7 @@ U8G2_SH1106_128X64_NONAME_F_HW_I2C lcd(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); -int fpsmicros = 0; +int oledfpsmicros = 0; // #if (SSD1306_LCDHEIGHT != 64) // #error("Height incorrect, please fix Adafruit_SSD1306.h!"); @@ -64,26 +182,48 @@ void whiteText(){ // display.display(); // } -void print_oled(String str,uint8_t size,bool flush){ +/** + * print oled lines + * @param str string to print + * @param no line 0-3 + * @param size text size 1-2 + */ +void print_oled_line(String str,uint16_t no = 1,uint16_t size = 1){ + uint16_t y = 0; + if(size == 1) y = 9*no; + if(size == 2) y = 18*no; + lcd.setCursor(0,y); + // lcd.setTextSize(size); + lcd.println(str); +} + +void print_oled(String str,uint8_t size = 1,bool flush = true){ lcd.clearBuffer(); // clear the internal memory - lcd.setFont(u8g2_font_ncenB08_tr); - lcd.drawStr(0,10,String(micros()).c_str()); // write something to the internal memory - lcd.setFont(u8g2_font_inb30_mn); - lcd.drawStr(0,60,str.c_str()); + // lcd.setFont(u8g2_font_ncenB08_tr); + // lcd.drawStr(0,10,String(micros()).c_str()); // write something to the internal memory + // lcd.setFont(u8g2_font_inb30_mn); + lcd.drawStr(10,30,str.c_str()); // lcd.drawStr(0,10,micros().c_str(); // write something to the internal memory if(flush)lcd.sendBuffer(); // transfer internal memory to the display } -void init_oled(bool preamble){ - Serial.println("\nInitializing SSD1106 OLED"); - Serial.println("SDA: "+(String)SDA); - Serial.println("SCL: "+(String)SCL); - Wire.begin(5,4); // begin(sda, scl) SWAP! - // Wire.begin(); // begin(sda, scl) SWAP! - Wire.setClock(400000L); - // lcd.setDisplayRotation(U8G2_R2); +void init_oled(bool preamble = true,uint8_t addr = 0x7A,bool pinswap = false){ + Logger.println("[OLED] Initializing SSD1106 OLED"); + Logger.println("[OLED] SDA: "+(String)SDA); + Logger.println("[OLED] SCL: "+(String)SCL); + if(pinswap){ + Wire.begin(5,4); // begin(sda, scl) SWAP! + Logger.println("[OLED] pinswapped"); + Logger.println("[OLED] SDA: "+(String)SDA); + Logger.println("[OLED] SCL: "+(String)SCL); + } + // Wire.setClock(400000L); + #ifdef ROT + lcd.setDisplayRotation(U8G2_R2); + #endif + // lcd.setBusClock(100000L); lcd.begin(); - // lcd.setI2CAddress(0x07a); + lcd.setI2CAddress(addr); // if(!lcd.begin()) { // Address 0x3C for 128x32 // Serial.println(F("SSD1106 begin failed")); // } @@ -114,14 +254,21 @@ void init_oled(bool preamble){ lcd.println("Booting...."); lcd.display(); delay(1000); - lcd.clearDisplay(); - lcd.display(); + lcd.clearBuffer(); + lcd.sendBuffer(); } void displayFPS(){ - lcd.print((String)(1000000/((micros()-fpsmicros)/2))); + String str = (String)((1000000/((micros()-oledfpsmicros)))); + // String str = (String)((micros()-oledfpsmicros)); + oledfpsmicros = micros(); + lcd.clearBuffer(); // clear the internal memory + lcd.drawStr(0,10,String(str+ " FPS").c_str()); + // lcd.drawStr(60,px,String(micros()).c_str()); // write something to the internal memory + lcd.sendBuffer(); // println(" FPS"); - fpsmicros = micros(); + // delay(300); + // delay(950); } // void printInverted(const char* str){ @@ -141,7 +288,7 @@ int printInverted(const char* str,uint16_t posx,uint16_t posy){ int padx = (lcd.getStrWidth("OFF")-lcd.getStrWidth("ON"))/2; // w padding // int pady = 2; // h padding int pady = 1; // h padding - Serial.println(padx); + // Serial.println(padx); lcd.setDrawColor(1); uint16_t strw = lcd.drawStr(posx+padx, posy, str); // x,y(NEGATIVE GOING!) @@ -164,9 +311,32 @@ int printValuePair(const char* str,String strb,int x,int y){ return xoff; // get new cursor? } +void oled_test(uint8_t num = 0){ + // print_oled_line(msg, line, size); + for(uint8_t i=0;i +#include + +#include + +#ifdef U8X8_HAVE_HW_SPI +#include +#endif +#ifdef U8X8_HAVE_HW_I2C +#include +#endif + + +// const char WIFI_SYMBOL[] = { 93,94,123,168, 176, 247, 253, 263, 277,278,279,280,281, '\0'}; +#define GLYPH_BELL 93 // bell +#define GLYPH_BT 94 // bt +#define GLYPH_CLOCK 123 // clock +#define GLYPH_FLAME 168 // flame +#define GLYPH_CHART 176 // chart +#define GLYPH_SIGNAL 253 // bell +#define GLYPH_SPARK 96 // bell +#define GLYPH_GEAR 129 // bell +#define GLYPH_ALERT 0x118 // bell +#define GLYPH_SPKOFF 0x117 // bell +#define GLYPH_SPKHI 0x115 // bell +#define GLYPH_SPKLO 0x116 // bell +#define GLYPH_HASHF 177 // bell +#define GLYPH_HASHM 178 // bell +#define GLYPH_HASHC 179 // bell +#define GLYPH_HDOTS 155 // bell +#define GLYPH_HBAR 221 // bell +#define GLYPH_CROSS 218 // bell +#define GLYPH_CROSSB 234 // bell +#define GLYPH_EKG 238 // bell +#define GLYPH_WIFI 0x119 // bell +#define GLYPH_WRENCH 0x120 // bell +#define GLYPH_TARGET 0x107 // bell +#define GLYPH_LISTINV 0x101 // bell +#define GLYPH_STAR 0x102 // bell +#define GLYPH_SUN 0x103 // bell +#define GLYPH_STPWTCH 269 // bell +#define GLYPH_TERM 0x109 // bell +#define GLYPH_DEL 0x121 // bell +#define GLYPH_GOOD 120 // bell +#define GLYPH_BAD 121 // bell +#define GLYPH_HEART 183 // bell +#define GLYPH_HOUSE 184 // bell +#define GLYPH_SQUARE 217 // bell +#define GLYPH_SPACE 287 // bell +#define GLYPH_NO 87 // busted +#define GLYPH_COFFEE 2615 // busted + +// const char* testing = u8"\u0263\u0BA3\u0B82"; + +// lcd.setFont(u8g2_font_open_iconic_embedded_1x_t); +// lcd.setFont(u8g2_font_open_iconic_all_1x_t); +// lcd.drawStr(0,y,WIFI_SYMBOL); +// lcd.drawUTF8(0,y,testing); +// lcd.drawGlyph(0,y, 93); // bell +// lcd.drawGlyph(10,y, 94); // bluetooth +// lcd.drawGlyph(20,y, 123); // clock +// lcd.drawGlyph(30,y, 168); // flame +// lcd.drawGlyph(40,y, 176); // chart +// lcd.drawGlyph(50,y, 253); // signal +// lcd.drawGlyph(60,y, 96); // terminus +// lcd.drawGlyph(70,y, 129); // gear +// lcd.drawGlyph(80,y, 0x118); // alert +// lcd.drawGlyph(90,y, 0x117); // speaker off +// lcd.drawGlyph(100,y, 0x115); // speaker high +// lcd.drawGlyph(110,y, 0x116); // speaker med + +// lcd.drawGlyph(0,y, 177); // hash fine +// lcd.drawGlyph(10,y, 178); // hash med +// lcd.drawGlyph(20,y, 179); // hash low +// lcd.drawGlyph(30,y, 155); // 3 dots +// lcd.drawGlyph(40,y, 221); // mid bar +// lcd.drawGlyph(50,y, 218); // cross +// lcd.drawGlyph(60,y, 234); // cross +// lcd.drawGlyph(60,y, 238); // heartbeat + +// lcd.drawGlyph(40,y,0x119); // wifi +// lcd.drawGlyph(50,y,0x120); // wrench not working +// lcd.drawGlyph(60,y,0x107); // target +// lcd.drawGlyph(70,y,0x101); // list inverted +// lcd.drawGlyph(80,y,0x102); // star +// lcd.drawGlyph(90,y,0x103); // sunshine +// lcd.drawGlyph(100,y,269); // stopwatch +// lcd.drawGlyph(110,y,0x109); // terminal +// lcd.drawGlyph(120,y,0x121); // delete +// +// +// lcd.drawGlyph(70,y, 120); // good +// lcd.drawGlyph(80,y, 121); // bad +// lcd.drawGlyph(90,y, 183); // heart +// lcd.drawGlyph(100,y, 184); // house +// lcd.drawGlyph(110,y, 217); // square +// // lcd.drawGlyph(110,y, 287); // space + +// if(glyphanimstate==0){ +// lcd.drawGlyph(120,y, 155); // +// glyphanimstate = 1; +// } +// else{ +// lcd.drawGlyph(120,y, 287); // +// glyphanimstate = 0; +// } + + +// https://github.com/olikraus/u8g2/wiki/fntlistall#24-pixel-height +// U8g2 Font names +// '_' '_' +// Description +// t Transparent font, Do not use a background color. +// h All glyphs have common height. +// m All glyphs have common height and width (monospace). +// 8 All glyphs fit into a 8x8 pixel box. +// Description +// f The font includes up to 256 glyphs. +// r Only glyphs on the range of the ASCII codes 32 to 127 are included in the font. +// u Only glyphs on the range of the ASCII codes 32 to 95 (uppercase chars) are included in the font. +// n Only numbers and extra glyphs for writing date and time strings are included in the font. +// ... Other custom character list. + +// #define WHITE SH110X_WHITE +// #define BLACK SH110X_BLACK + +// #define SH1106_128_64 +// #define SCREEN_WIDTH 128 // OLED display width, in pixels +// #define SCREEN_HEIGHT 64 // OLED display height, in pixels + + +// U8G2_SSD1306_128X64_NONAME_F_SW_I2C lcd(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display +U8G2_SSD1306_128X64_NONAME_F_HW_I2C lcd(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); + +int oledfpsmicros = 0; + +// #if (SSD1306_LCDHEIGHT != 64) +// #error("Height incorrect, please fix Adafruit_SSD1306.h!"); +// #endif + +void invertText(){ + lcd.setDrawColor(2); + // lcd.setTextColor(BLACK, WHITE); // 'inverted' text +} + +void whiteText(){ + lcd.setDrawColor(1); + // lcd.setTextColor(WHITE); // 'inverted' text +} + +// void init_oled(){ +// init_oled(false); +// } + +// void init_oled(){ +// Wire.begin(SCL,SDA); // begin(sda, scl) SWAP! +// // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally +// if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32 +// Serial.println(F("SSD1306 allocation failed")); +// } + +// display.clearDisplay(); +// display.setTextSize(1); // Normal 1:1 pixepl scale +// display.setTextColor(WHITE); // Draw white text +// display.setCursor(0,0); // Start at top-left corner +// display.display(); +// } + +/** + * print oled lines + * @param str string to print + * @param no line 0-3 + * @param size text size 1-2 + */ +void print_oled_line(String str,uint16_t no = 1,uint16_t size = 1){ + uint16_t y = 10; + if(size == 1) y += 9*no; + if(size == 2) y += 18*no; + lcd.setCursor(10,y); + // lcd.setTextSize(size); + lcd.println(str); +} + +void print_oled(String str,uint8_t size = 1,bool flush = true){ + lcd.clearBuffer(); // clear the internal memory + // lcd.setFont(u8g2_font_ncenB08_tr); + // lcd.drawStr(0,10,String(micros()).c_str()); // write something to the internal memory + lcd.setFont(u8g2_font_inb30_mn); + lcd.drawStr(10,30,str.c_str()); + // lcd.drawStr(0,10,micros().c_str(); // write something to the internal memory + if(flush)lcd.sendBuffer(); // transfer internal memory to the display +} + +void init_oled(bool preamble = true,bool pinswap = false,uint16_t rotate = 2){ + Logger.println("[OLED] Initializing SSD1106 OLED"); + Logger.println("[OLED] SDA: "+(String)SDA); + Logger.println("[OLED] SCL: "+(String)SCL); + if(pinswap){ + Wire.begin(SDA,SCL); // begin(sda, scl) SWAP! + Logger.println("[OLED] pinswapped"); + Logger.println("[OLED] SDA: "+(String)SDA); + Logger.println("[OLED] SCL: "+(String)SCL); + } + // Wire.setClock(400000L); + if(rotate==2){ + // #define U8G2_R0 (&u8g2_cb_r0) + // #define U8G2_R1 (&u8g2_cb_r1) + // #define U8G2_R2 (&u8g2_cb_r2) + // #define U8G2_R3 (&u8g2_cb_r3) + // #define U8G2_MIRROR (&u8g2_cb_mirror) + lcd.setDisplayRotation(U8G2_R2); + } + + // lcd.setBusClock(100000L); + lcd.begin(); + // lcd.setI2CAddress(0x78); + // if(!lcd.begin()) { // Address 0x3C for 128x32 + // Serial.println(F("SSD1106 begin failed")); + // } + lcd.setFont(u8g2_font_ncenB08_tr); + // u8g2_font_inb30_mn + lcd.clearBuffer(); // clear the internal memory + + int px = 10; + lcd.clearBuffer(); // clear the internal memory + lcd.drawStr(0,px,"Starting..."); + // lcd.drawStr(60,px,String(micros()).c_str()); // write something to the internal memory + lcd.sendBuffer(); // transfer internal memory to the display + + return; + // Wire.setClock(400000L); // set i2c speed 400khz + // Wire.setClock(100000L); // set i2c speed 400khz + + // lcd.clearDisplay(); + // lcd.setTextSize(1); // Normal 1:1 pixepl scale + // lcd.setCursor(0,0); // Start at top-left corner + // lcd.setTextColor(WHITE); // REQUIRED! + // lcd.display(); + // delay(1000); + if(!preamble) return; + + // lcd.setTextSize(1); + lcd.setCursor(0,0); + lcd.println("Booting...."); + lcd.display(); + delay(1000); + lcd.clearBuffer(); + lcd.sendBuffer(); +} + +void displayFPS(){ + String str = (String)((1000000/((micros()-oledfpsmicros)))); + // String str = (String)((micros()-oledfpsmicros)); + oledfpsmicros = micros(); + lcd.clearBuffer(); // clear the internal memory + lcd.drawStr(10,10,String(str+ " FPS").c_str()); + lcd.drawStr(30,10,String(micros()).c_str()); // write something to the internal memory + lcd.sendBuffer(); + // println(" FPS"); + // delay(300); + // delay(950); +} + +// void printInverted(const char* str){ +// lcd.setFontMode(1); +// lcd.print(str); +// lcd.setFontMode(0); +// } + + +int printInverted(const char* str,uint16_t posx,uint16_t posy){ + int lh = lcd.getAscent()+abs(lcd.getDescent()); // font height ? + + // int posy = px*2; // posy VAR + // int posx = 0; // posy VAR +// Serial.println(lcd.getStrWidth("OFF")); +// Serial.println(lcd.getStrWidth("ON")); + int padx = (lcd.getStrWidth("OFF")-lcd.getStrWidth("ON"))/2; // w padding + // int pady = 2; // h padding + int pady = 1; // h padding + // Serial.println(padx); + lcd.setDrawColor(1); + uint16_t strw = lcd.drawStr(posx+padx, posy, str); // x,y(NEGATIVE GOING!) + + lcd.setFontMode(1); + lcd.setDrawColor(2); + lcd.drawBox(posx, (posy-lh)+pady, strw+(padx*2),lh); // x,y(POSITIVE GOING!),w,h + + lcd.setDrawColor(1); // restore default + return strw+(padx*2); +} + +void printInvertedStr(String str,uint16_t posx,uint16_t posy){ + printInverted(str.c_str(),posx,posy); +} + +int printValuePair(const char* str,String strb,int x,int y){ + int xoff = printInverted(str,x,y); + lcd.setCursor(x+xoff+5, y); + lcd.print(strb.c_str()); + return xoff; // get new cursor? +} + +void oled_test(uint8_t num = 0){ + // print_oled_line(msg, line, size); + for(uint8_t i=0;i // #include #include // https://github.com/br3ttb/Arduino-PID-Library +#include // [PIDTUNE] COMPLETE // P 97.403 @@ -22,9 +23,10 @@ // 1468.5591 // da fuq? -uint16_t fullPowerPeriod = 10000; // full power startup pulse period -bool fullPowerStartup = true; // enable full power period +uint16_t fullPowerPeriod = 8000; // full power startup pulse period +bool fullPowerStartup = false; // enable full power period if startup wanted temp is greater than 5 degrees(arb) +bool pidEnabled = false; int long pidTimerStart = 0; bool pidRunning = false; // flag is pid running, used for init start etc. @@ -34,12 +36,12 @@ bool isCuttoff = false; bool isFanOn = false; float lastWantedTemp = -1; -bool DEBUG_pid = false; +bool DEBUG_pid = true; //Define Variables we'll be connecting to double Setpoint, Input, Output; -float integatorReset = 0.75; // when to reset Ki +float integatorReset = 0.75; // when to reset Ki percent of delta 75% // profiling open // pulse 100% @ 23C @@ -106,6 +108,7 @@ float integatorReset = 0.75; // when to reset Ki double KpLite = 4, KiLite = .5, KdLite = 0; // slight undershoot, needs a little more power on ramp and peak double Kp = 13, Ki = .5, Kd = 0; // slight undershoot, needs a little more power on ramp and peak +// double Kp = 5, Ki = .1, Kd = 0; // slight undershoot, needs a little more power on ramp and peak // agressive double KpAgr = 28, KiAgr = .5, KdAgr = 0; // slight undershoot, needs a little more power on ramp and peak @@ -164,39 +167,46 @@ PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT); void pid_reset_I(){ myPID.SetTunings(Kp, 0, Kd); + // Logger.println("[PID] reset I"); + // Logger.println("[PID] PID : " + (String)Kp + " 0 " + (String)Kd); } void pid_preset_I(){ myPID.SetTunings(Kp, Ki, Kd); + // Logger.println("[PID] preset I"); + // Logger.println("[PID] PID : " + (String)Kp + " " + (String)Ki + " " + (String)Kd); } void pid_peak(){ - Serial.println("[PID] adjust tunings"); myPID.SetTunings(KpAgr, KiAgr, KdAgr); + Logger.println("[PID] adjust tunings"); + Logger.println("[PID] PID : " + (String)KpAgr + " " + (String)KiAgr + " " + (String)KdAgr); // @todo confirm tunings } void init_PID(){ // float Kp=97.403, Ki=3.142, Kd=754.9, Hz=10; - Serial.println("[PID] init"); - Serial.println("[PID] PID : " + (String)Kp + " " + (String)Ki + " " + (String)Kd); + Logger.println("[PID] init"); + Logger.println("[PID] PID : " + (String)Kp + " " + (String)Ki + " " + (String)Kd); myPID.SetMode(AUTOMATIC); myPID.SetOutputLimits(0,250); // depending on the ssr freq, low values do nothing < 5%, test this, even 1% will slowly add thermal over time // myPID.SetSampleTime(120); - // if(!res) Serial.println("[ERROR] init FAILED (outputrange)"); - // if(myPID.err()) Serial.println("[ERROR] init FAILED (construct)"); + // if(!res) Logger.println("[ERROR] init FAILED (outputrange)"); + // if(myPID.err()) Logger.println("[ERROR] init FAILED (construct)"); } void pidStart(){ pidTimerStart = millis(); - if(fullPowerStartup){ + if((currentTemp-currentTempAvg>5) && fullPowerStartup){ myPID.SetMode(MANUAL); Output = 250; // output never returns to normal !!!! } + // pidEnabled = true; pidRunning = true; } void run_PID(){ + // if(!pidEnabled) return; if(!pidRunning) pidStart(); // updateTemps(); // this is too close to the PID freq // make sure temps are updated before calling run pid, but do not run close to the same frequency @@ -215,12 +225,13 @@ void run_PID(){ // why is PID doing effort after setpoint if(Input > Setpoint && (Output > 1)){ - Serial.println("[PID] WTF PID"); + // Logger.println("[PID] WTF PID"); } - // Serial.print("-"); - // Serial.print(Output); + // Logger.print("-"); + // Logger.print(Output); if(fullPowerStartup){ if(millis()-pidTimerStart < fullPowerPeriod){ + // handled on startup atm } else if(myPID.GetMode() == MANUAL){ Output = 0; @@ -251,7 +262,7 @@ void MatchTemp() // set.lookAhead = 2; // set.lookAheadWarm = 2; - // Serial.print("."); + // Logger.print("."); // if(wantedTemp > 0) run_PID(); // return; float duty = 0; @@ -278,28 +289,28 @@ void MatchTemp() DEBUG_pid = currentDelta > 0; if(DEBUG_pid){ - Serial.print( "[PID]" ); + Logger.print( "[PID]" ); - // Serial.print( "T: " ); - // Serial.print( timeX ); + // Logger.print( "T: " ); + // Logger.print( timeX ); - Serial.print( " Current: " ); - Serial.print( currentTemp ); + Logger.print( " Current: " ); + Logger.print( currentTemp ); - Serial.print( " Wanted: " ); - Serial.print( wantedTemp ); + Logger.print( " Wanted: " ); + Logger.print( wantedTemp ); - Serial.print( " T Diff: " ); - Serial.print( tempDiff ); + Logger.print( " T Diff: " ); + Logger.print( tempDiff ); - Serial.print( " W Diff: " ); - Serial.print( wantedDiff ); + Logger.print( " W Diff: " ); + Logger.print( wantedDiff ); - Serial.print( " Perc: " ); - Serial.print( perc ); + Logger.print( " Perc: " ); + Logger.print( perc ); - Serial.print( " Delta: " ); - Serial.print( currentDelta ); + Logger.print( " Delta: " ); + Logger.print( currentDelta ); } float base = 128; @@ -316,27 +327,27 @@ if(DEBUG_pid){ base = constrain( base, 0, 256 ); if(DEBUG_pid){ - Serial.print(" Base: "); - Serial.print( base ); - // Serial.print( " -> " ); + Logger.print(" Base: "); + Logger.print( base ); + // Logger.print( " -> " ); } duty = base + ( 172 * perc ); // 172? if(DEBUG_pid){ - Serial.print(" Duty: "); - Serial.print( duty ); - Serial.print( " -> " ); - Serial.println(""); + Logger.print(" Duty: "); + Logger.print( duty ); + Logger.print( " -> " ); + Logger.println(""); } // if(duty<0)duty = 0; duty = constrain( duty, 0, 256 ); // override for full blast at start - // Serial.println("startFullBlast"); - // Serial.println(timeX); - // Serial.println(CurrentGraph().reflowGraphX[1]); + // Logger.println("startFullBlast"); + // Logger.println(timeX); + // Logger.println(CurrentGraph().reflowGraphX[1]); // if ( set.startFullBlast && (timeX < CurrentGraph().reflowGraphX[1]) ) duty = 256; // if ( set.startFullBlast && timeX < CurrentGraph().reflowGraphX[1] && currentTemp < wantedTemp ) duty = 256; setSSR( duty ); diff --git a/pidtune.h b/pidtune.h index d7fb983..d1d42fc 100644 --- a/pidtune.h +++ b/pidtune.h @@ -49,7 +49,7 @@ void init_pidtune(){ // tuner.setZNMode(PIDAutotuner::ZNModeNoOvershoot); // This must be called immediately before the tuning loop - tuner.startTuningLoop(); + tuner.startTuningLoop(micros()); // Run a loop until tuner.isFinished() returns true long microseconds; @@ -63,7 +63,7 @@ void init_pidtune(){ float input = doSomethingToGetInput(); // Call tunePID() with the input value - float output = tuner.tunePID(input); + float output = tuner.tunePID(input,micros()); // Set the output - tunePid() will return values within the range configured // by setOutputRange(). Don't change the value or the tuning results will be diff --git a/power_funcs.h b/power_funcs.h new file mode 100644 index 0000000..9f3c4a3 --- /dev/null +++ b/power_funcs.h @@ -0,0 +1,77 @@ +#ifndef power_funcs_h +#define power_funcs_h + +#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */ +#define TIME_TO_SLEEP 5 /* Time ESP32 will go to sleep (in seconds) */ + +RTC_DATA_ATTR int bootCount = 0; + +/* +Method to print the reason by which ESP32 +has been awaken from sleep +*/ +void print_wakeup_reason(esp_sleep_wakeup_cause_t wakeup_reason){ + switch(wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; + case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; + case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; + case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; + case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; + default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; + } +} + +void awoken(){ + //Increment boot number and print it every reboot + ++bootCount; + Serial.println("Boot number: " + String(bootCount)); + + + esp_sleep_wakeup_cause_t wakeup_reason; + wakeup_reason = esp_sleep_get_wakeup_cause(); + + if(!wakeup_reason) Serial.println("I Was not sleeping"); + else print_wakeup_reason(wakeup_reason); +} + +void shhhhhh_gotoSleep(){ + shhhhhh_gotoSleep(); +} +void shhhhhh_gotoSleep(uint32_t seconds = 60){ + + esp_sleep_enable_ext0_wakeup(GPIO_NUM_0,1); //1 = High, 0 = Low + Serial.println("Setup ESP32 to sleep with IO wake"); + + // esp_sleep_enable_timer_wakeup(seconds * uS_TO_S_FACTOR); + // Serial.println("Setup ESP32 to sleep for " + String(seconds) + " Seconds"); + + /* + Next we decide what all peripherals to shut down/keep on + By default, ESP32 will automatically power down the peripherals + not needed by the wakeup source, but if you want to be a poweruser + this is for you. Read in detail at the API docs + http://esp-idf.readthedocs.io/en/latest/api-reference/system/deep_sleep.html + Left the line commented as an example of how to configure peripherals. + The line below turns off all RTC peripherals in deep sleep. + */ + //esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF); + //Serial.println("Configured all RTC Peripherals to be powered down in sleep"); + + /* + Now that we have setup a wake cause and if needed setup the + peripherals state in deep sleep, we can now start going to + deep sleep. + In the case that no wake up sources were provided but deep + sleep was started, it will sleep forever unless hardware + reset occurs. + */ + Serial.println("Going to sleep now"); + Serial.flush(); + esp_deep_sleep_start(); + // zzzzzzzzzz +} + + + +#endif \ No newline at end of file diff --git a/reflow_pid.h b/reflow_pid.h index a8bcddd..37e4be9 100644 --- a/reflow_pid.h +++ b/reflow_pid.h @@ -1,6 +1,9 @@ #ifndef reflow_pid_h #define reflow_pid_h +// remove all reflowoven methods, use for all SSR pid control generic +// + #include "InterpolationLib.h" unsigned long stateStartMS = 0; // state start timers @@ -11,7 +14,7 @@ int reflowGraphCounter = 0; // counter period for graphing graphInterval // temperature vars int hotTemp = 70; // C burn temperature for HOT indication, 0=disable -int coolTemp = 50; // C safe temperature for HOT indication, 0=disable +int coolTemp = 48; // C safe temperature for HOT indication, 0=disable int lowTemp = 30; // C of TC warmed than typical CJ int shutDownTemp = 210; // degrees C int fanTemp = lowTemp+5; // cooldown complete fan off low temp diff --git a/sense_env.h b/sense_env.h new file mode 100644 index 0000000..87ec9e5 --- /dev/null +++ b/sense_env.h @@ -0,0 +1,1607 @@ +#ifndef sensors_h +#define sensors_h + +#include + +Average avg_a(20); + +// @todo +// add global env_debug +// add local status for each sensor, avoid sending bad values if init failed +// add improved scanner, default addresses have higher weight, if sensor already detected with high probability, reduce weight + +// SUPPORTED SENSORS + +// SHT31 +// SHT21 +// HTU21D +// +// BMP280 - !reads 40k alt when offline, 0 psi, 0 temp +// BME280 +// CS811 - CO2 +// TSL2561 +// BH1750 - https://github.com/claws/BH1750 +// APDS9960 +// GP2Y +// PMs - PM2.5 Dust sensors https://github.com/avaldebe/PMserial +// MPU6050 +// PCF8591 +// SCD4x - CO2 sensor +// VEML6070 - UV (highly conflicting address space) +// SI7021 +// AHTx0 - T/H (highly conflicting address space) +// SGP30 - tvoc +// INA219 - current + +// NOT IMPLEMENTED @TODO + +// HMC5883L +// MAX9814 +// MCP3421 +// MCP4725 +// MCP3421 +// SGP40 - tvoc AQI +// SGP41 - tvoc +// ENS160 - tvoc + +// BUGS +// sensors do not reinit if they drop out, add heathcheck() +// co2 voc, resubmits the same value over and over if device is lost +// use real temp and humidity to compensate other sensors + +#include +#include + +// I2C + +// MOTION +// =============== +// #define MPU6050 // MPU 6050 GY521 3axis gyro/accel +// #define HMC5883L // NI Honeywell HMC5883L +// #define MLX90393 // 3 axis magnetometer + +// TEMP/HUMIDITY/GAS +// ================= +// #define SI7021 +// #define AHTX0 +#define SGP30 // mox gas/tvoc and raw + + +// Sensiron +// ================ +#define USESHT40 // SHT40 Temp/Humidity +// #define USESHT31 // SHT31 Temp/Humidity +// #define USESHT21 // SHT21 / HTU21D Temp/Humidity + + +// BOSCH +// ================= +// #define USEBMP180 // BMP180 Temp/Pressure/Altitude (replaces BMP085) https://www.adafruit.com/product/1603 + + +/* +Vin: 3 to 5VDC +Logic: 3 to 5V compliant +Pressure sensing range: 300-1100 hPa (9000m to -500m above sea level) +Up to 0.03hPa / 0.25m resolution +-40 to +85°C operational range, +-2°C temperature accuracy +This board/chip uses I2C 7-bit address 0x77. +*/ + +// #define USEBMP280 // BMP280 Temp/Pressure/Altitude (upgrade for BMP085/BMP180/BMP183) +// #define USEBME280 // BME280 Humidity/Pressure/Altitude +// Pressure: 300...1100 hPa + +#define SCD40 // SDC40 Co2/Temp/Humidity +// #define USECS811 // CCS811 Temp/CO2/VOC +// #define USEGP2Y // Sharp Particle/Dust sensor GP2Y1010AU0F, GP2Y1014AU0F +#define PMSx // pms7003 + + +// LIGHT +// ================ +// #define APDS9960 // Proximity, Light, RGB, and Gesture Sensor +// #define USEBH1750 // Light Sensor + +/* + BH1750 has six different measurement modes. They are divided in two groups; + continuous and one-time measurements. In continuous mode, sensor continuously + measures lightness value. In one-time mode the sensor makes only one + measurement and then goes into Power Down mode. + + Each mode, has three different precisions: + + - Low Resolution Mode - (4 lx precision, 16ms measurement time) + - High Resolution Mode - (1 lx precision, 120ms measurement time) + - High Resolution Mode 2 - (0.5 lx precision, 120ms measurement time) + + By default, the library uses Continuous High Resolution Mode, but you can + set any other mode, by passing it to BH1750.begin() or BH1750.configure() + functions. + + [!] Remember, if you use One-Time mode, your sensor will go to Power Down + mode each time, when it completes a measurement and you've read it. + + Full mode list: + + BH1750_CONTINUOUS_LOW_RES_MODE + BH1750_CONTINUOUS_HIGH_RES_MODE (default) + BH1750_CONTINUOUS_HIGH_RES_MODE_2 + + BH1750_ONE_TIME_LOW_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE + BH1750_ONE_TIME_HIGH_RES_MODE_2 +*/ + + +// #define VEML6070 // UV Sensor + + +// #define TSL2561 // Luminosity/Lux/Light Address = 0x39 //Slave addr also 0x29 or 0x49 +/* +TSL2561 +Approximates Human eye Response +Precisely Measures Illuminance in Diverse Lighting Conditions +Temperature range: -30 to 80 *C +Dynamic range (Lux): 0.1 to 40,000 Lux +Voltage range: 2.7-3.6V +Interface: I2C + +TSL2591 ++ +Approximates Human eye Response +Extremely wide dynamic range 1 to 600,000,000 Counts +Lux Range: 188 uLux sensitivity, up to 88,000 Lux input measurements. +Temperature range: -30 to 80 *C +Voltage range: 3.3-5V into onboard regulator +Interface: I2C + +*/ + +// SOUND +// ============== +// #define MAX9814 // MAX9814 Auto GC amplifier +// #define MAX4466 // MAX4466 Adj GC amplifier + +// Energy +// =============== +// #define INA219 // INA219 current sense + +// IO +// =============== +// #define MCP4725 // 12bit DAC with EEPROM +// #define MCP3421 // 18bit delta-sigma ADC +// #define PCF8591 // PCF8591 io expander + + +// ADDRESSES +// ================ +// (7bit) (8bit) (*)typical default +// 0x23 0x46 BH1750* +// 0x38 0x70 VEML6070* / AHTx0* +// 0x39 0x72 APDS9960* / TSL2561 / VEML6070 / AHTx0 +// 0x3C 0x78 +// 0x44 0x88 +// 0x48 0x90 +// 0x5A 0xB4 CS811* +// 0x62 0xC4 SCD4X* +// 0x68 0xD0 +// 0x76 0xEC +// 0x77 0xEE +// 0x0D 0x1A MLX90393 + +/* +#ifdef ENV_TEMPLATE +#include + +void init_env(){ + bool ret = false; + ret = env.begin(); + if(!ret){ + Logger.println("[ERROR] _env init FAILED"); + } + else Logger.println("[ENV] _env is ACTIVE"); + // return ret; +} + +void print_env(){ +} + +float get_env(uint8_t channel = 0){ + // print_env(); + if(channel == 0) return _env.readvalue(); + // if(channel == 1) return ; + // if(channel == 2) return ; +} +#endif +*/ + +// ADC Sensors +// ADC I2C + +// ESP32 ADC + +// MCP3421 +// + +/* +ANALOG PRESSURE SENDER +--30 psi +Input: 0-30 psi +Output: 0.5V~4.5V linear voltage output. 0 psi outputs 0.5V, 15psi outputs 2.5V, 30 psi outputs 4.5V. +Accuracy: within 2% of reading (full scale). +Thread: 1/8"-27 NPT. +Wiring Connector: Water sealed quick disconnect. Mating connector is included. +Wiring: Red for +5V; Black for ground; Blue for signal output. +*/ + + +//ONEWIRE + +#ifdef DS18B20 +#include +#include +// The DallasTemperature library can do all this work for you! +// http://milesburton.com/Dallas_Temperature_Control_Library +#define _DS18B20Pin 14 +// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) +OneWire oneWire(ONE_WIRE_BUS); + + +// url=https://github.com/milesburton/Arduino-Temperature-Control-Library +// Pass our oneWire reference to Dallas Temperature. +DallasTemperature _DS18B20(&oneWire); +// DallasTemperature _DS18B20[oneWireCount]; + +uint8_t _DS18B20_num_sensors = 3; +DeviceAddress _DS18B20Addr[_DS18B20_num_sensors]; + +void init_DS18B20(){ + bool ret = false; + + // oneWire.setPin(_DS18B20Pin); + _DS18B20.setOneWire(_DS18B20Pin); + ret = _DS18B20.begin(); + + if(!ret){ + Logger.println("[ERROR] _DS18B20 init FAILED"); + } + else Logger.println("[ENV] _DS18B20 is ACTIVE"); + // return ret; + + //oneWire.reset_search(); + + for(size_t i=0; i<_DS18B20_num_sensors; i++){ + _DS18B20.getAddress(_DS18B20Addr[i], i); // get address + _DS18B20.setResolution(_DS18B20Addr[i], 9); // set precision + // _DS18B20.getResolution(_DS18B20Addr[i], DEC); + } + +} + +void print_DS18B20(){ + float tempC = _DS18B20.getTempCByIndex(0); + + // Check if reading was successful + if(tempC != DEVICE_DISCONNECTED_C) + { + Serial.print("Temperature for the device 1 (index 0) is: "); + Serial.println(tempC); + } + else + { + Serial.println("Error: Could not read temperature data"); + } +} + +float get_DS18B20(uint8_t channel = 0){ + _DS18B20.requestTemperatures(); + // for (int i = 0; i < oneWireCount; i++) { + // sensor[i].requestTemperatures(); + // } + // print_env(); + if(channel == 0) return _DS18B20.getTempCByIndex(0); + if(channel == 1) return _DS18B20.getTempCByIndex(1); + if(channel == 2) return _DS18B20.getTempCByIndex(2); + // if(channel == 1) return ; + // if(channel == 2) return ; +} +#endif + + +#ifdef VEML6070 + +// PRODUCT SUMMARY +// PART NUMBER +// OPERATING VOLTAGE RANGE +// (V)2.7 to 5.5 +// I2C BUS VOLTAGE RANGE +// (V) 1.7 to 5.5 +// PEAK SENSITIVITY +// (nm) 355 +// RANGE OF SPECTRAL BANDWIDTH λ0.5 +// (nm) ± 20 +// OUTPUT CODE 16 bit, I2C +// VEML6070 + +// Slave Address and Function Description +// The VEML6070 has one slave address used for write functions (command) and two slave addresses used for read functions +// (UV data LSB and MSB). +// The 7-bit address for write functions is 38h = 0111000x resulting in a 70h = 01110000 8-bit address. The 7-bit addresses +// for read functions are 38h = 0111000x for the UV Data LSB and 39h = 0111001x for the UV data MSB. This results in a +// 71h = 01110001 and 73h = 01110011 8-bit address, respectively. The 7-bit address 39h should not be used for a write function. + +#include "Adafruit_VEML6070.h" + +Adafruit_VEML6070 env_veml6070 = Adafruit_VEML6070(); + +void init_veml6070(){ + bool ret = true; // NI + env_veml6070.begin(VEML6070_1_T); // pass in the integration time constant + if(!ret){ + Logger.println("[ERROR] _veml6070 init FAILED"); + } + else Logger.println("[ENV] _veml6070 is ~ACTIVE"); + // return ret; +} + +void print_veml6070(){ +} + +float get_veml6070(uint8_t channel = 0){ + // print_env(); + if(channel == 0) return env_veml6070.readUV(); + return 0; +} +#endif + + +#ifdef PMSx // particulate matter / DUST sensor + +#ifndef ESP32 +#include +#endif + +#include // Arduino library for PM sensors with serial interface + +bool pms_debug = false; +// pass in pins, define does not work +#if !defined(PMS_RX) && !defined(PMS_TX) +constexpr auto PMS_RX = 3; +constexpr auto PMS_TX = 4; +#endif + +#ifndef ESP32 +SerialPM pms(PMS5003, PMS_RX, PMS_TX); // PMSx003, RX, TX + +// Alternative: +//SoftwareSerial SoftSerial1(PMS_RX, PMS_TX); +//SerialPM pms(PMS5003, SoftSerial1); +#else +SerialPM pms(PMS5003, PMS_RX, PMS_TX); // PMSx003, RX, TX +#endif + +bool init_pms(){ + // Logger.println(F("PMS sensor on SWSerial")); + // Logger.print(F(" RX:")); + // Logger.println(PMS_RX); + // Logger.print(F(" TX:")); + // Logger.println(PMS_TX); + bool ret = true; + pms.init(); + if(!ret){ + Logger.println("[ERROR] pms init FAILED"); + } + else Logger.println("[ENV] pms is ACTIVE"); + return ret; +} + +void print_pms_status(){ + Logger.print("[ENV] pms status: "); + switch (pms.status) + { + case pms.OK: // should never come here + Logger.println("OK"); + break; // included to compile without warnings + case pms.ERROR_TIMEOUT: + Logger.println(F(PMS_ERROR_TIMEOUT)); + break; + case pms.ERROR_MSG_UNKNOWN: + Logger.println(F(PMS_ERROR_MSG_UNKNOWN)); + break; + case pms.ERROR_MSG_HEADER: + Logger.println(F(PMS_ERROR_MSG_HEADER)); + break; + case pms.ERROR_MSG_BODY: + Logger.println(F(PMS_ERROR_MSG_BODY)); + break; + case pms.ERROR_MSG_START: + Logger.println(F(PMS_ERROR_MSG_START)); + break; + case pms.ERROR_MSG_LENGTH: + Logger.println(F(PMS_ERROR_MSG_LENGTH)); + break; + case pms.ERROR_MSG_CKSUM: + Logger.println(F(PMS_ERROR_MSG_CKSUM)); + break; + case pms.ERROR_PMS_TYPE: + Logger.println(F(PMS_ERROR_PMS_TYPE)); + break; + } + } + +void print_pms(){ + // print the results + Logger.print(F("PM1.0 ")); + Logger.print(pms.pm01); + Logger.print(F(", ")); + Logger.print(F("PM2.5 ")); + Logger.print(pms.pm25); + Logger.print(F(", ")); + Logger.print(F("PM10 ")); + Logger.print(pms.pm10); + Logger.println(F(" [ug/m3]")); + + if(!pms_debug) return; + + print_pms_status(); + + if (pms.has_number_concentration()) + { + Serial.print(F("N0.3 ")); + Serial.print(pms.n0p3); + Serial.print(F(", ")); + Serial.print(F("N0.5 ")); + Serial.print(pms.n0p5); + Serial.print(F(", ")); + Serial.print(F("N1.0 ")); + Serial.print(pms.n1p0); + Serial.print(F(", ")); + Serial.print(F("N2.5 ")); + Serial.print(pms.n2p5); + Serial.print(F(", ")); + Serial.print(F("N5.0 ")); + Serial.print(pms.n5p0); + Serial.print(F(", ")); + Serial.print(F("N10 ")); + Serial.print(pms.n10p0); + Serial.println(F(" [#/100cc]")); + } + + if (pms.has_temperature_humidity() || pms.has_formaldehyde()) + { + Serial.print(pms.temp, 1); + Serial.print(F(" °C")); + Serial.print(F(", ")); + Serial.print(pms.rhum, 1); + Serial.print(F(" %rh")); + Serial.print(F(", ")); + Serial.print(pms.hcho, 2); + Serial.println(F(" mg/m3 HCHO")); + } +} + +float get_pms(uint8_t channel = 0){ + // print_env(); + if(channel == 0){ + pms.read(); + return pms.pm01; + } + if(channel == 1) return pms.pm25; + if(channel == 2) return pms.pm10; + if(channel == 3) return pms.n0p3; + if(channel == 4) return pms.n0p5; + if(channel == 5) return pms.n1p0; + if(channel == 6) return pms.n2p5; + if(channel == 7) return pms.n5p0; + if(channel == 8) return pms.n10p0; + return 0; +} + +#endif + +#ifdef PCF8591 +#include + +// TwoWire Wire_B = TwoWire(); +// Wire_B.setClock(100000); +// Wire_B.setClockStretchLimit(); +// adafruit_i2c bool setSpeed(uint32_t desiredclk); + +// Make sure that this is set to the value in volts of VCC +#define ADC_REFERENCE_VOLTAGE 5.0 +Adafruit_PCF8591 pcf = Adafruit_PCF8591(); + +bool init_PCF8591(){ + bool ret = false; + ret = pcf.begin(); + if(!ret){ + Logger.println("[ERROR] PCF8591 init FAILED"); + return false; + } + else Logger.println("[ENV] PCF8591 is ACTIVE"); + pcf.enableDAC(true); + return ret; +} + +float int_to_volts(uint16_t dac_value, uint8_t bits, float logic_level) { + return (((float)dac_value / ((1 << bits) - 1)) * logic_level); +} + +float get_PCF8591(uint8_t channel = 0, bool volts=false){ + Wire.setClock(100000L); + // print_env(); + if(volts){ + if(channel == 0) return int_to_volts(pcf.analogRead(0), 8, ADC_REFERENCE_VOLTAGE); + if(channel == 1) return int_to_volts(pcf.analogRead(1), 8, ADC_REFERENCE_VOLTAGE); + if(channel == 2) return int_to_volts(pcf.analogRead(2), 8, ADC_REFERENCE_VOLTAGE); + if(channel == 3) return int_to_volts(pcf.analogRead(3), 8, ADC_REFERENCE_VOLTAGE); + } + else { + if(channel == 0) return pcf.analogRead(0); + if(channel == 1) return pcf.analogRead(1); + if(channel == 2) return pcf.analogRead(2); + if(channel == 3) return pcf.analogRead(3); + } + Wire.setClock(400000L); +} + +void print_PCF8591(){ + pcf.analogWrite(random(128)+128); + for(int i=0;i<4;i++){ + Logger.print(get_PCF8591(i)); + } + Logger.println(""); + for(int i=0;i<4;i++){ + Logger.print(get_PCF8591(i,true)); + } + Logger.println(""); +} + +#endif + + +#ifdef INA219 +#include + +Adafruit_INA219 ina219; + +bool init_INA219(){ + bool ret = false; + ret = ina219.begin(); + if(!ret){ + Logger.println("[ERROR] INA219 init FAILED"); + } + else Logger.println("[ENV] INA219 is ACTIVE"); + return ret; +} + +void print_INA219(){ + float shuntvoltage = 0; + float busvoltage = 0; + float current_mA = 0; + float loadvoltage = 0; + float power_mW = 0; + + shuntvoltage = ina219.getShuntVoltage_mV(); + busvoltage = ina219.getBusVoltage_V(); + current_mA = ina219.getCurrent_mA(); + power_mW = ina219.getPower_mW(); + loadvoltage = busvoltage + (shuntvoltage / 1000); + + Logger.print("Bus Voltage: "); Logger.print(busvoltage); Logger.println(" V"); + Logger.print("Shunt Voltage: "); Logger.print(shuntvoltage); Logger.println(" mV"); + Logger.print("Load Voltage: "); Logger.print(loadvoltage); Logger.println(" V"); + Logger.print("Current: "); Logger.print(current_mA); Logger.println(" mA"); + Logger.print("Power: "); Logger.print(power_mW); Logger.println(" mW"); + Logger.println(""); +} + +float get_INA219(uint8_t channel = 0){ + print_INA219(); + float shuntvoltage = ina219.getShuntVoltage_mV(); + float busvoltage = ina219.getBusVoltage_V(); + if(channel == 0) return shuntvoltage; + if(channel == 1) return busvoltage; + if(channel == 2) return ina219.getCurrent_mA(); + if(channel == 3) return ina219.getPower_mW(); + if(channel == 4) return busvoltage + (shuntvoltage / 1000); + return 0; +} +#endif + + +#ifdef MPU6050 +// 3.3V onboard ldo for 5v +#include +#include + +Adafruit_MPU6050 mpu; + +bool init_mpu6050(){ + bool ret = false; + ret = mpu.begin(); + + // mpu.setAccelerometerRange(MPU6050_RANGE_2_G); + // mpu.setAccelerometerRange(MPU6050_RANGE_4_G); + mpu.setAccelerometerRange(MPU6050_RANGE_8_G); + // mpu.setAccelerometerRange(MPU6050_RANGE_16_G); + + // mpu.setGyroRange(MPU6050_RANGE_250_DEG); + mpu.setGyroRange(MPU6050_RANGE_500_DEG); + // mpu.setGyroRange(MPU6050_RANGE_1000_DEG); + // mpu.setGyroRange(MPU6050_RANGE_2000_DEG); + + // mpu.setFilterBandwidth(MPU6050_BAND_260_HZ); + // mpu.setFilterBandwidth(MPU6050_BAND_184_HZ); + // mpu.setFilterBandwidth(MPU6050_BAND_94_HZ); + // mpu.setFilterBandwidth(MPU6050_BAND_44_HZ); + mpu.setFilterBandwidth(MPU6050_BAND_21_HZ); + // mpu.setFilterBandwidth(MPU6050_BAND_10_HZ); + // mpu.setFilterBandwidth(MPU6050_BAND_5_HZ); + + + if(!ret){ + Logger.println("[ERROR] MPU6050 init FAILED"); + } + else Logger.println("[ENV] MPU6050 gyro/accel is ACTIVE"); + return ret; +} + +void print_mpu6050(){ + sensors_event_t a, g, temp; + mpu.getEvent(&a, &g, &temp); + + /* Print out the values */ + Logger.print("Acceleration X: "); + Logger.print(a.acceleration.x); + Logger.print(", Y: "); + Logger.print(a.acceleration.y); + Logger.print(", Z: "); + Logger.print(a.acceleration.z); + Logger.println(" m/s^2"); + + Logger.print("Rotation X: "); + Logger.print(g.gyro.x); + Logger.print(", Y: "); + Logger.print(g.gyro.y); + Logger.print(", Z: "); + Logger.print(g.gyro.z); + Logger.println(" rad/s"); + + Logger.print("Temperature: "); + Logger.print(temp.temperature); + Logger.println(" degC"); +} + +float get_mpu6050(uint8_t channel = 0){ + // print_mpu6050(); + sensors_event_t a, g, temp; + mpu.getEvent(&a, &g, &temp); + // accel m/s^2 + if(channel == 0) return a.acceleration.x; + if(channel == 1) return a.acceleration.y; + if(channel == 2) return a.acceleration.z; + + // gyro rad/s + if(channel == 3) return g.gyro.x; + if(channel == 4) return g.gyro.y; + if(channel == 5) return g.gyro.z; + return 0; +} + +#endif + + + +#ifdef USEBH1750 +#include +// 2.4V to 3.6V +BH1750 lightMeter(0x23); + +bool init_BH1750(){ + bool ret = false; + ret = lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE); + if(!ret){ + Logger.println("[ERROR] BH1750 init FAILED"); + } + else Logger.println("[ENV] BH1750 is ACTIVE"); + return ret; +} + +void print_BH1750(){ +} + +float get_BH1750(uint8_t channel = 0){ + // print_env(); + if (lightMeter.measurementReady()){ + if(channel == 0) return (float)lightMeter.readLightLevel(); + if(channel == 1) return 0; + if(channel == 2) return 0; + } + return 0; +} +#endif + + +// #ifdef BH1750_B +// #include //inlude the library +// hp_BH1750 env_BH1750_B; + +// // BH1750Address addr = BH1750_TO_VCC; +// // BH1750Address BH1750addr = BH1750_TO_GROUND; +// // 0x23/0x5A , or 0X5C +// // BH1750_TO_GROUND = 0x23, +// // BH1750_TO_VCC = 0x5C + +// void print_bh1750(){ +// if (env_BH1750_B.hasValue() == true) { // non blocking reading +// float lux = env_BH1750_B.getLux(); +// Logger.println("[ENV] lux"); +// Logger.println(lux); +// env_BH1750_B.start(); +// } +// } + +// bool init_bh1750(){ +// bool status = env_BH1750_B.begin(BH1750_TO_GROUND); // will be false no sensor found +// // use BH1750_TO_GROUND or BH1750_TO_VCC depending how you wired the address pin of the sensor. + +// // BH1750.calibrateTiming(); //uncomment this line if you want to speed up your sensor +// env_BH1750_B.start(); +// // BH1750.start(BH1750_QUALITY_HIGH2, mtreg); +// // BH1750.setQuality(mode); + +// if(!status) Logger.println("[ERROR] BH1750 init FAILED"); +// else Logger.println("[ENV] BH1750 Device is ACTIVE"); + +// return status; +// } + +// float get_bh1750(uint8_t channel = 0){ +// float lux; +// if(channel == 0){ +// Logger.println("env_BH1750_B get channel 0"); +// if (env_BH1750_B.hasValue() == true) { // non blocking reading +// Logger.println("env_BH1750_B has value"); +// lux = env_BH1750_B.getLux(); +// env_BH1750_B.start(); +// Logger.println(lux); +// } +// } +// else{ +// env_BH1750_B.start(); //starts a measurement +// lux=env_BH1750_B.getLux(); +// Logger.println(lux); +// } +// return lux; +// } +// #endif + + +#ifdef APDS9960 +// 2.4V to 3.6V +#include "Adafruit_APDS9960.h" +Adafruit_APDS9960 apds; +uint8_t apds_int_pin = -1; + +// apds_addr = ; + +bool init_apds(){ + bool ret = false; + ret = apds.begin(); + if(!ret){ + Logger.println("[ERROR] APDS9960 init FAILED"); + } + else Logger.println("[ENV] APDS9960 is ACTIVE"); + if(apds_int_pin > 0) pinMode(apds_int_pin, INPUT_PULLUP); + return ret; +} + +void init_apds_color(){ + //enable color sensing mode + apds.enableColor(true); +} + +void init_apds_proximity(){ + if(apds_int_pin > 0) pinMode(apds_int_pin, INPUT_PULLUP); + //enable proximity mode + apds.enableProximity(true); + //set the interrupt threshold to fire when proximity reading goes above 175 + apds.setProximityInterruptThreshold(0, 175); + //enable the proximity interrupt + apds.enableProximityInterrupt(); +} + +void init_apds_gesture(){ + apds.enableProximity(true); + apds.enableGesture(true); +} + +// NOT interrupt +String get_apds_proximity(){ + if(!digitalRead(apds_int_pin)){ + Logger.println(apds.readProximity()); + + //clear the interrupt + apds.clearInterrupt(); + } + return ""; +} + +String get_apds_gesture(){ + uint8_t gesture = apds.readGesture(); + if(gesture == APDS9960_DOWN) Logger.println("v"); + if(gesture == APDS9960_UP) Logger.println("^"); + if(gesture == APDS9960_LEFT) Logger.println("<"); + if(gesture == APDS9960_RIGHT) Logger.println(">"); + return ""; +} + +void print_apds_color(){ + uint16_t r, g, b, c, cnt; + //wait for color data to be ready + while(!apds.colorDataReady() && cnt <100){ + delay(5); + cnt++; + } + + //get the data and print the different channels + apds.getColorData(&r, &g, &b, &c); + Logger.print("red: "); + Logger.print(r); + + Logger.print(" green: "); + Logger.print(g); + + Logger.print(" blue: "); + Logger.print(b); + + Logger.print(" clear: "); + Logger.println(c); + Logger.println(); +} + +float get_apds_color(uint8_t channel = 0){ + // print_apds_color(); + uint16_t r, g, b, c; + while(!apds.colorDataReady()){ + delay(5); + } + if(!apds.colorDataReady()) return 0; + apds.getColorData(&r, &g, &b, &c); + if(channel == 0) return r; + if(channel == 1) return g; + if(channel == 2) return b; + if(channel == 3) return c; + return 0; +} + +#endif + + +#ifdef USEGP2Y +#include +const uint8_t SHARP_LED_PIN = 27; // Sharp Dust/particle sensor Led Pin +const uint8_t SHARP_VO_PIN = 33; // Sharp Dust/particle analog out pin used for reading +uint16_t gp2y_avgnumsamples = 10; // running average samples +uint16_t gp2y_numsamples = 5; // num samples to return + +// GP2Y1010AU0F +// GP2Y1014AU0F +GP2YDustSensor dustSensor(GP2YDustSensorType::GP2Y1014AU0F, SHARP_LED_PIN, SHARP_VO_PIN, gp2y_avgnumsamples); +#endif + +#ifdef USEGP2Y +void init_gp2y(){ + dustSensor.setBaseline(0.1); // set no dust voltage according to your own experiments + //dustSensor.setCalibrationFactor(1.1); // calibrate against precision instrument + dustSensor.begin(); + + // * Set sensitivity in volts/100ug/m3 + // * Typical sensitivity is 0.5V, set by default + // * GP2Y1010AU0F sensitivity: min/typ/max: 0.425 / 0.5 / 0.75 + // * GP2Y1014AU0F sensitivity: min/typ/max: 0.35 / 0.5 / 0.65 + // dustSensor.setSensitivity(); + + // getBaselineCandidate(); + // setBaseline(); +} + +float get_gp2y(uint8_t channel = 0){ + // print_bmp280(); + if(channel == 0) return dustSensor.getDustDensity(gp2y_numsamples); + if(channel == 1) return dustSensor.getRunningAverage(); + if(channel == 2) return analogRead(SHARP_VO_PIN); +} + +String print_gp2y(){ + // Logger.print("Dust density: "); + Logger.print(dustSensor.getDustDensity(gp2y_numsamples)); + // Logger.print(" ug/m3; Running average: "); + Logger.print("\t"); + Logger.print(dustSensor.getRunningAverage()); + // Logger.println(" ug/m3"); + Logger.print("\t"); + Logger.print(analogRead(SHARP_VO_PIN)); + Logger.println(""); +} +#endif + +#ifdef USELM75 +#include +// Create I2C LM75A instance +LM75A lm75(true, //A0 LM75A pin state + true, //A1 LM75A pin state + true); //A2 LM75A pin state +#endif + +// SHT31 Temp/Humidity +#ifdef USESHT31 +#include +Adafruit_SHT31 sht31 = Adafruit_SHT31(); +#endif + +// BMP280 Temp/Pressure/Altitude +#ifdef USEBMP280 +#include +Adafruit_BMP280 bmp; // I2C +// #define BMP280_ADDRESS (0x77) /**< The default I2C address for the sensor. */ +// #define BMP280_ADDRESS_ALT (0x76) +#endif + +#ifdef USEBMP280 +void init_bmp280(){ + if (!bmp.begin(BMP280_ADDRESS)) { + Logger.println(F("[ERROR] BMP280 init FAILED")); + } + else Logger.println(F("[ENV] BMP280 is ACTIVE")); + + /* Default settings from datasheet. */ + bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ +} + +void print_bmp280(){ + Logger.print(F("Status")); + Logger.println((String)bmp.getStatus()); + Logger.print(F("Temperature = ")); + Logger.print(bmp.readTemperature()); + Logger.println(" *C"); + + Logger.print(F("Pressure = ")); + Logger.print(bmp.readPressure()); + Logger.println(" Pa"); + + Logger.print(F("Approx altitude = ")); + Logger.print(bmp.readAltitude(1013.25)); /* Adjusted to local forecast! */ + Logger.println(" m"); + + Logger.println(); +} + +// BUGGY returns bad values not null, or noint +float get_bmp280(uint8_t channel = 0){ + // print_bmp280(); + if(channel == 0) return bmp.readTemperature(); + if(channel == 1) return bmp.readPressure(); + if(channel == 2) return bmp.readAltitude(1013.25); + return 0; +} + +#endif + +#ifdef USESHT31 +bool enableHeater = false; +uint8_t loopCnt = 0; + +void init_sht31(){ + bool init = sht31.begin(0x44); + if(init){ + Logger.println(F("[ENV] SHT31 is ACTIVE")); + } + else + { + Logger.println(F("[ERROR] SHT31 init FAILED")); + } + + Logger.print("Heater Enabled State: "); + if (sht31.isHeaterEnabled()) Logger.println("ENABLED"); + else Logger.println("DISABLED"); +} + +String getSHT31Temperature(){ + float t = sht31.readTemperature(); + if(isnan(t)) return ""; + return (String) t; +} + +String getSHT31Humidity(){ + float h = sht31.readHumidity(); + if(isnan(h)) return ""; + return (String) h; +} + +void print_sht31(){ + float t = sht31.readTemperature(); + float h = sht31.readHumidity(); + + if (! isnan(t)) { // check if 'is not a number' + Logger.print("Temp *C = "); Logger.print(t); Logger.print("\t\t"); + } else { + Logger.println("Failed to read temperature"); + } + + if (! isnan(h)) { // check if 'is not a number' + Logger.print("Hum. % = "); Logger.println(h); + } else { + Logger.println("Failed to read humidity"); + } +} + +void sht31_process(){ + // Toggle heater enabled state every 30 seconds + // An ~3.0 degC temperature increase can be noted when heater is enabled + if (++loopCnt == 30) { + enableHeater = !enableHeater; + sht31.heater(enableHeater); + Logger.print("[ENV] SHT31 Heater State: "); + if (sht31.isHeaterEnabled()) + Logger.println("ENABLED"); + else + Logger.println("DISABLED"); + + loopCnt = 0; + } +} +#endif + +#ifdef USESHT40 +// SHT4x Temp/Humidity +#include "Adafruit_SHT4x.h" +Adafruit_SHT4x sht4 = Adafruit_SHT4x(); + +bool enableHeater = false; + +bool init_sht4(){ + + bool init = sht4.begin(); + if(init){ + Logger.println(F("[ENV] SHT4x is ACTIVE")); + } + else + { + Logger.println(F("[ERROR] SHT4x init FAILED")); + } + + // Logger.print("[ENV] SHT4x Serial number 0x"); + // Logger.println(sht4.readSerial()); // HEX crashes logger + + // You can have 3 different precisions, higher precision takes longer + sht4.setPrecision(SHT4X_MED_PRECISION); + // switch (sht4.getPrecision()) { + // case SHT4X_HIGH_PRECISION: + // Logger.println("High precision"); + // break; + // case SHT4X_MED_PRECISION: + // Logger.println("Med precision"); + // break; + // case SHT4X_LOW_PRECISION: + // Logger.println("Low precision"); + // break; + // } + + // You can have 6 different heater settings + // higher heat and longer times uses more power + // and reads will take longer too! + sht4.setHeater(SHT4X_NO_HEATER); + // switch (sht4.getHeater()) { + // case SHT4X_NO_HEATER: + // Logger.println("No heater"); + // break; + // case SHT4X_HIGH_HEATER_1S: + // Logger.println("High heat for 1 second"); + // break; + // case SHT4X_HIGH_HEATER_100MS: + // Logger.println("High heat for 0.1 second"); + // break; + // case SHT4X_MED_HEATER_1S: + // Logger.println("Medium heat for 1 second"); + // break; + // case SHT4X_MED_HEATER_100MS: + // Logger.println("Medium heat for 0.1 second"); + // break; + // case SHT4X_LOW_HEATER_1S: + // Logger.println("Low heat for 1 second"); + // break; + // case SHT4X_LOW_HEATER_100MS: + // Logger.println("Low heat for 0.1 second"); + // break; + // } + return init; +} + +// BUGGY returns bad values not null, or noint +float get_sht4(uint8_t channel = 0){ + // async ? + sensors_event_t humidity, temp; + sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data + if(channel == 0) return temp.temperature; + if(channel == 1) return humidity.relative_humidity; + return 0; +} + +void sht4_process(){ + sensors_event_t humidity, temp; + uint32_t timestamp = millis(); + sht4.getEvent(&humidity, &temp);// populate temp and humidity objects with fresh data + timestamp = millis() - timestamp; + + Serial.print("Temperature: "); Serial.print(temp.temperature); Serial.println(" degrees C"); + Serial.print("Humidity: "); Serial.print(humidity.relative_humidity); Serial.println("% rH"); + + Serial.print("Read duration (ms): "); + Serial.println(timestamp); + + // // Toggle heater enabled state every 30 seconds + // // An ~3.0 degC temperature increase can be noted when heater is enabled + // if (++loopCnt == 30) { + // enableHeater = !enableHeater; + // sht31.heater(enableHeater); + // Logger.print("[ENV] SHT40 Heater State: "); + // if (sht4.isHeaterEnabled()) + // Logger.println("ENABLED"); + // else + // Logger.println("DISABLED"); + + // loopCnt = 0; + // } +} + +#endif + + +// SHT21 / HTU21D Temp/Humidity +#ifdef USESHT21 +#include +/* +resolution: +HTU21D_RES_RH12_TEMP14 - RH: 12Bit, Temperature: 14Bit, by default +HTU21D_RES_RH8_TEMP12 - RH: 8Bit, Temperature: 12Bit +HTU21D_RES_RH10_TEMP13 - RH: 10Bit, Temperature: 13Bit +HTU21D_RES_RH11_TEMP11 - RH: 11Bit, Temperature: 11Bit +*/ +HTU21D myHTU21D(HTU21D_RES_RH12_TEMP14); // 0x40 + +void init_sht21(){ + bool init = myHTU21D.begin(); + if(init){ + Logger.println(F("[ENV] HTU21D, SHT21 is ACTIVE")); + } + else{ + Logger.println(F("[ERROR] HTU21D, SHT21 init FAILED")); //(F()) saves string to flash & keeps dynamic memory free + } + + delay(1000); + init = myHTU21D.begin(); + // while (myHTU21D.begin(SCL,SDA) != true) + // { + // Logger.println(F("HTU21D, SHT21 sensor is failed or not connected")); //(F()) saves string to flash & keeps dynamic memory free + // delay(5000); + // } + // Logger.println(F("HTU21D, SHT21 sensor is active")); +} + +String getSHT21Humidity(){ + return (String)myHTU21D.readCompensatedHumidity(); +} + +void print_sht21(){ + /* DEMO - 1 */ + // Logger.println(F("DEMO 1: 12-Bit Resolution")); + Logger.print(F("Humidity............: ")); + Logger.println(myHTU21D.readHumidity()); + // Logger.println(F(" +-2%")); + + Logger.print(F("Compensated Humidity: ")); + Logger.println(myHTU21D.readCompensatedHumidity()); + // Logger.println(F(" +-2%")); + + // Logger.println(F("DEMO 1: 14-Bit Resolution")); + Logger.print(F("Temperature.........: ")); + Logger.println(myHTU21D.readTemperature()); + // Logger.println(F(" +-0.3C")); + return; + + /* DEMO - 2 */ + Logger.println(F("DEMO 2: 11-Bit Resolution")); + myHTU21D.setResolution(HTU21D_RES_RH11_TEMP11); + Logger.print(F("Humidity............: ")); + Logger.print(myHTU21D.readHumidity()); + Logger.println(F(" +-2%")); + + Logger.print(F("Compensated Humidity: ")); + Logger.print(myHTU21D.readCompensatedHumidity()); + Logger.println(F(" +-2%")); + + Logger.println(F("DEMO 2: 11-Bit Resolution")); + Logger.print(F("Temperature.........: ")); + Logger.print(myHTU21D.readTemperature()); + Logger.println(F(" +-0.3C")); + + /* DEMO - 3 */ + Logger.println(F("DEMO 3: Battery Status")); + if(myHTU21D.batteryStatus() == true){ + Logger.println(F("Battery.............: OK. Level > 2.25v")); + } + else { + Logger.println(F("Battery.............: LOW. Level < 2.25v")); + } + + /* DEMO - 4 */ + Logger.println(F("DEMO 4:")); + Logger.print(F("Firmware version....: ")); + Logger.println(myHTU21D.readFirmwareVersion()); + + + /* DEMO - 5 */ + Logger.println(F("DEMO 5:")); + Logger.print(F("Sensor's ID.........: ")); + Logger.println(myHTU21D.readDeviceID()); + + + /* back to lib. default resolution */ + myHTU21D.softReset(); + myHTU21D.setResolution(HTU21D_RES_RH12_TEMP14); +} + + +float get_sht21(uint8_t channel = 0){ + if(channel == 0) return myHTU21D.readTemperature(); + if(channel == 1) return myHTU21D.readCompensatedHumidity(); + if(channel == 2) return myHTU21D.readHumidity(); + return 0; +} + +#endif + + + +#ifdef USELM75 +void init_LM75(){ +} + +void print_LM75(){ + Logger.println((String)lm75.getTemperatureInFahrenheit() + " F"); +} +#endif + +// ************************************************************* +// CCS811 Temp/CO2/VOC +// 0x5A or 0x5B +#ifdef USECS811 +#include "Adafruit_CCS811.h" +Adafruit_CCS811 ccs; + +void init_cs811(){ + int starttime = millis(); + if(!ccs.begin()){ + Logger.println("[ERROR] CS811 init FAILED"); + } + else { + Logger.println("[ENV] CS811 is ACTIVE"); + //calibrate temperature sensor + while(!ccs.available() && millis() < starttime+5000); + float temp = ccs.calculateTemperature(); + Logger.println("[ENV] CS811 set offset " + String(temp-25.0)); + ccs.setTempOffset(temp - 25.0); + } + // ccs.setDriveMode(uint8_t mode); + ccs.readData(); +} + +void print_cs811(){ + if(ccs.available()){ + float temp = ccs.calculateTemperature(); + if(!ccs.readData()){ + Logger.print("CO2: "); + Logger.print(ccs.geteCO2()); + Logger.print("ppm, TVOC: "); + Logger.print(ccs.getTVOC()); + Logger.print("ppb Temp:"); + Logger.println(temp); + } + } + else{ + Logger.println("[ERROR] cs811 not available"); // + } +} + +// first call usually fails? +float get_cs811(uint8_t channel = 0){ + // print_cs811(); + // if(!ccs.available()) return 0; + // if(ccs.readData()) return 0; + // @todo detect failures, or else func return old values + // if(!ccs.available()) Logger.println("[ERROR] cs811 not available"); // always false? + if(ccs.checkError()) Logger.println("[ERROR] Assert cs811 check error"); // always false? + uint8_t err = ccs.readData(); + float ret; + if(err != 0) Logger.println("[ERROR] cs811 readData " + (String)err); + if(channel == 0) ret = ccs.calculateTemperature(); + if(channel == 1) ret = ccs.geteCO2(); + if(channel == 2) ret = ccs.getTVOC(); + if(channel == 3) ret = ccs.getCurrentSelected(); + return ret; +} +#endif + + +/** + * [filterSensor description] + * @param {[type]} float n [description] + * @param {[type]} a low limit + * @param {[type]} b high limit + * @param {String} c replace + * @return {[type]} [description] + */ +String filterSensor( float n, float a,float b,String c = ""){ + if(n <= a ) return c; + if(n >= b ) return c; + return (String)n; +} + +String truncateSensor(float n,uint8_t precision = 0){ + if(precision = 0) return (String)(int)n; + return (String)n; +} + +// #define USEINTVCC +#ifdef USEINTVCC +#ifdef ESP32 + extern "C" int rom_phy_get_vdd33(); +#endif + +float getVoltage(){ + #ifdef ESP32 + float voltage = ((float)rom_phy_get_vdd33()) / 1000; + return voltage; + #endif +} +#endif + + + +#ifdef SCD40 +#include +SensirionI2CScd4x scd4x; +// CO2 0x62 +void init_scd4x(){ + uint16_t error; + char errorMessage[256]; + scd4x.begin(Wire); + + // stop potentially previously started measurement + error = scd4x.stopPeriodicMeasurement(); + if (error) { + Serial.print("Error trying to execute stopPeriodicMeasurement(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + } else error = true; + + error = scd4x.startPeriodicMeasurement(); + + if(error){ + Serial.print("Error trying to execute startPeriodicMeasurement(): "); + errorToString(error, errorMessage, 256); + Serial.println(errorMessage); + Logger.println("[ERROR] SCD4X init FAILED"); + } + else Logger.println("[ENV] SCD4X is ACTIVE"); + // return ret; +} + +float get_scd4x(uint8_t channel = 0,bool update=true){ + static uint16_t scd4x_co2; + static float scd4x_temperature; + static float scd4x_humidity; + static uint16_t scd4x_error = 0; + if(update){ + char errorMessage[256]; + scd4x_error = scd4x.readMeasurement(scd4x_co2, scd4x_temperature, scd4x_humidity); + if(scd4x_error){ + Serial.print("Error trying to execute readMeasurement(): "); + errorToString(scd4x_error, errorMessage, 256); + Serial.println(errorMessage); + } + } + if(channel == 0) return scd4x_co2; + if(channel == 1) return scd4x_temperature; + if(channel == 2) return scd4x_humidity; + if(channel == 3) return scd4x_error; + return 0; +} + +void print_scd4x(){ + + Serial.print(__FUNCTION__); + Serial.print(" co2: "); + Serial.print(get_scd4x(0)); + Serial.print(" temp: "); + Serial.print(get_scd4x(1,false)); + Serial.print(" humidity: "); + Serial.print(get_scd4x(2,false)); + Serial.print(" error: "); + Serial.println(); +} + +#endif + + +#ifdef USEBMP180 +#include +Adafruit_BMP085 bmp180; +void init_bmp180(){ + bool ret = false; + ret = bmp180.begin(); + if(!ret){ + Logger.println("[ERROR] BMP180 init FAILED"); + } + else Logger.println("[ENV] BMP180 is ACTIVE"); + // return ret; +} + +void print_bmp180(){ + Logger.print("Temperature = "); + Logger.print(bmp.readTemperature()); + Logger.println(" *C"); + + Logger.print("Pressure = "); + Logger.print(bmp.readPressure()); + Logger.println(" Pa"); + + // Calculate altitude assuming 'standard' barometric + // pressure of 1013.25 millibar = 101325 Pascal + Logger.print("Altitude = "); + Logger.print(bmp.readAltitude()); + Logger.println(" meters"); + + Logger.print("Pressure at sealevel (calculated) = "); + Logger.print(bmp.readSealevelPressure()); + Logger.println(" Pa"); + + // you can get a more precise measurement of altitude + // if you know the current sea level pressure which will + // vary with weather and such. If it is 1015 millibars + // that is equal to 101500 Pascals. + Logger.print("Real altitude = "); + Logger.print(bmp.readAltitude(101500)); + Logger.println(" meters"); + + Logger.println(); +} + +float get_bmp180(uint8_t channel = 0){ + // print_env(); + if(channel == 0) return bmp180.readTemperature(); + if(channel == 1) return bmp180.readPressure(); + if(channel == 2) return bmp180.readAltitude(); + if(channel == 3) return bmp180.readSealevelPressure(); + if(channel == 4) return bmp180.readAltitude(101500); + return 0; +} +#endif + + +#ifdef AHTX0 +// #define AHTX0_I2CADDR_DEFAULT 0x38 ///< AHT default i2c address +// #define AHTX0_I2CADDR_ALTERNATE 0x39 ///< AHT alternate i2c address +#include +Adafruit_AHTX0 aht; + +void init_aht(){ + bool ret = false; + ret = aht.begin(); + if(!ret){ + Logger.println("[ERROR] aht init FAILED"); + } + else Logger.println("[ENV] aht is ACTIVE"); + // return ret; +} + +void print_aht(){ +} + +float get_aht(uint8_t channel = 0){ + sensors_event_t humidity, temp; + aht.getEvent(&humidity, &temp); + // print_env(); + if(channel == 0) return temp.temperature; + if(channel == 1) return humidity.relative_humidity; + return 0; +} +#endif + +#ifdef SGP30 +#include "Adafruit_SGP30.h" +Adafruit_SGP30 sgp; + +void init_sgp30(){ + Logger.println("[ENV] init_sgp30"); + bool ret = false; + ret = sgp.begin(); + if(!ret){ + Logger.println("[ERROR] _sgp30 init FAILED"); + } + else Logger.println("[ENV] _sgp30 is ACTIVE"); + + // If you have a baseline measurement from before you can assign it to start, to 'self-calibrate' + // sgp.setIAQBaseline(0x8E68, 0x8F41); // Will vary for each sensor! + // return ret; + + // If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals + //float temperature = 22.1; // [°C] + //float humidity = 45.2; // [%RH] + //sgp.setHumidity(getAbsoluteHumidity(temperature, humidity)); + +} + +void print_sgp30(){ + // Logger.print("Found SGP30 serial #"); + // Logger.print(sgp.serialnumber[0], HEX); + // Logger.print(sgp.serialnumber[1], HEX); + // Logger.println(sgp.serialnumber[2], HEX); + + if (! sgp.IAQmeasure()) { + Logger.println("Measurement failed"); + return; + } + Logger.print("TVOC "); Logger.print(sgp.TVOC); Logger.println(" ppb\t"); + Logger.print("eCO2 "); Logger.print(sgp.eCO2); Logger.println(" ppm"); + + if (! sgp.IAQmeasureRaw()) { + Logger.println("Raw Measurement failed"); + return; + } + Logger.print("Raw H2 "); Logger.println(sgp.rawH2); + Logger.print("Raw Ethanol "); Logger.println(sgp.rawEthanol); + + uint16_t TVOC_base, eCO2_base; + if (! sgp.getIAQBaseline(&eCO2_base, &TVOC_base)) { + Logger.println("Failed to get baseline readings"); + return; + } + Logger.print("****Baseline values: \neCO2: 0x"); Logger.println(eCO2_base, HEX); + Logger.print("TVOC: 0x"); Logger.println(TVOC_base, HEX); +} + +float get_sgp30(uint8_t channel = 0){ + // print_sgp30(); + if(sgp.IAQmeasure()){ + if(channel == 0) return sgp.TVOC; + if(channel == 1) return sgp.eCO2; + + if(sgp.IAQmeasureRaw()){ + if(channel == 2) return sgp.rawH2; + if(channel == 3) return sgp.rawEthanol; + } + } + + return 0; +} +#endif + +/* return absolute humidity [mg/m^3] with approximation formula +* @param temperature [°C] +* @param humidity [%RH] +*/ +uint32_t getAbsoluteHumidity(float temperature, float humidity) { + // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15 + const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3] + const uint32_t absoluteHumidityScaled = static_cast(1000.0f * absoluteHumidity); // [mg/m^3] + return absoluteHumidityScaled; +} + +#endif \ No newline at end of file diff --git a/sense_env_class.h b/sense_env_class.h new file mode 100644 index 0000000..2e38bfd --- /dev/null +++ b/sense_env_class.h @@ -0,0 +1,156 @@ +// sense env class + +// create sensor instance + +// sensor add +// max num samples +// ring buffer +// ring index +// sensor id +// sensor index +// sensor mqtt topic (temp/temp2/humidity) +// sensor i2c addr +// sensor unit +// sensor values or sensor group by type + +// sensor calc +// avg +// mean +// mode +// running avg +// khalman filter +// validation/rejection/clamping + +// timestamp or period reconstructor + +// sensor alarms/threshholds + +// offline mode/collection/logging to sd, maybe add a second buffer with long term ogging interval + +// interrupt for sense_env sensor + +// depencandies +// average +// statsistics +// filter + +// ability to grab a sample window for deferred submission to mqtt for a series ( useful for battery operated devices or offline ) +// ability to grab lastvalue as running average over subset of last n samples/n times +// ability to reject oulier values for known bad sensor values lacking error conditions + +// get sensors by group/id for looping to displays etc + +#ifndef sensorsdlog_h +#define sensorsdlog_h + +// #include +#include +// using namespace std; + +#include +// Average avg_a(20); + +// #include +// Statistic myStats; + +// vector or list of sensor objects +// group by type for sensors with many metrics +// addSensor(char* id, char* name, char* unit, T datatype); +// removeSensor(char* id); +// getSensorByID(char* id); +// vector sensors; // how to use a templated class here? + +// collections of sensors +// T datatype +template +class sensorcollection { + private: + std::vector> sensors; + // sensors.resize() + uint32_t _numsamples = 20; + + public: + sensorcollection(); + ~sensorcollection(); + void begin(); + void addSensor(int idx, uint8_t size); + void addSensorValue(int idx, T value); + float getSensorValue(int idx); + +}; + + template + sensorcollection::sensorcollection(){ + Serial.println("sensorcollection constructor"); + // testing in constructor for now + // BUT how to create many new instances and retain them in class? + // Average avg_x(_numsamples); // scope this in class?, surely this will go bye bye + } + + template + sensorcollection::~sensorcollection(){ + Serial.println("sensorcollection de-constructor"); + sensors.clear(); + } + + template + void sensorcollection::begin(){ + sensors.push_back(Average(_numsamples)); // use temp obj or smart pointers? + } + + template + void sensorcollection::addSensor(int idx, uint8_t size){ + Average *avg_x = new Average(size); + sensors.push_back(*avg_x); // use temp obj or smart pointers? + Serial.println("added sensor: " + (String)idx); + } + + template + void sensorcollection::addSensorValue(int idx, T value){ + sensors[idx].push(value); + } + + template + float sensorcollection::getSensorValue(int idx){ + return sensors[idx].mean(); + } + +// // individual sensor log, one per value +// // or find a way to create anonymous objects, but each one might have different units so might as well keep them seperate. +// template +// class sensordlog { +// private: + +// const char* _id; // unique id of collection +// const char* _name; // name +// char* _unit; // units of values eg. ug/L +// T datatype; // template of typename of sample, float, int etc +// int _numsamples = 20; // number of samples to store in buffer + +// public: +// sensordlog(); // add inializer list or use setters? +// ~sensordlog(); + +// // setSensorRange(T min, T max); +// // setSensorNumSamples(int numSamples); + +// // getValue(char* id); // self.value() +// // getAvg(); //self.avg() +// // getMean(); +// // getMode(); +// // getMax(); +// // getMin(); + +// // extended +// // pass in pointer funcs for specific library methods +// // init() +// // update() +// }; + + +// template sensordlog::sensordlog(){ +// Serial.println("constructor"); +// // sensors.push_back(Statistic myStats1); // ? how to use an anoymous object pointer in vector? +// } + +#endif \ No newline at end of file diff --git a/sensor_env_class.cpp b/sensor_env_class.cpp new file mode 100644 index 0000000..47cf379 --- /dev/null +++ b/sensor_env_class.cpp @@ -0,0 +1,5 @@ +// #include "sense_env_class.h" + +// void sensordlog::sensordlog(){ +// Serial.println("constructor"); +// } \ No newline at end of file diff --git a/serialcmd.h b/serialcmd.h index d534dbd..3c4050a 100644 --- a/serialcmd.h +++ b/serialcmd.h @@ -2,9 +2,9 @@ #define serialcmd_h #include -#include -#include -#include +#include // @todo remove +#include // @todo remove +#include // @todo remove // HardwareSerial DebugOut = Serial; // HardwareSerial DebugOut(0); diff --git a/snippets.h b/snippets.h index d072aa6..3692f43 100644 --- a/snippets.h +++ b/snippets.h @@ -1,3 +1,5 @@ + +// proper rollover handling if (micros () - then > some_interval) { // do something diff --git a/ssr.h b/ssr.h index 83cba7a..bf2a693 100644 --- a/ssr.h +++ b/ssr.h @@ -1,30 +1,41 @@ #ifndef ssr_h #define ssr_h -#define RELAYPIN 16 // relay control SSR PWM +#define RELAYPIN 3 // relay control SSR PWM #include +#include +#include + +#define DEBUG #ifdef DEBUG bool DEBUG_ssr = true; #else bool DEBUG_ssr = false; #endif - + +bool ssrDisabled = true; // safety ON float currentDuty = 0; // ssrpower -bool invertDuty = true; // invert logic vcc range +bool invertDuty = true; // invert duty logic vcc range, true for low side sinking, pwm is high pulse +bool invertLOW = !invertDuty; // Drive SSR with VCC // invert logic for 2 state relay, this is usually opposite of invertDuty int _ssrRelayPin = -1; -void ssr_init(int pin){ - _ssrRelayPin = pin; - pinMode( _ssrRelayPin, OUTPUT ); - digitalWrite(_ssrRelayPin,HIGH); - +void ssr_init(uint16_t pin){ #ifdef ESP8266 analogWriteRange(255); // esp8266 - // analogWriteFreq(240); // min 100hz + // analogWriteFreq(120); // min 100hz #elif defined(ESP32) - #endif + // analogWriteResolution(_ssrRelayPin, 8); + #endif + + //ssr enable + + Logger.println("[SSR] READY on pin " + (String)_ssrRelayPin); + _ssrRelayPin = pin; + // ssr_off(); + digitalWrite(_ssrRelayPin, invertLOW ? LOW : HIGH); + pinMode( _ssrRelayPin, OUTPUT ); } void ssr_init(){ @@ -34,6 +45,7 @@ void ssr_init(){ // This is where the SSR is controlled via PWM void SetSSRFrequency( int duty,int power =1) { + if(duty!=currentDuty){ // calculate the wanted duty based on settings power override duty = ((float)duty * power ); // power adjust duty = constrain( round_f( duty ), 0, 255); // round and clamp @@ -41,27 +53,60 @@ void SetSSRFrequency( int duty,int power =1) // Write the clamped duty cycle to the RELAYPIN GPIO int out = invertDuty ? 255-duty : duty; - #ifdef ESP8266P - analogWrite( _ssrRelayPin, out); - #endif - // if(duty == 0)digitalWrite(RELAYPIN,invertDuty ? LOW:HIGH); - // if(duty == 255)digitalWrite(RELAYPIN,!invertDuty ? LOW:HIGH); - if(duty!=currentDuty){ - // if(DEBUG_ssr) Serial.println("[SSR] " + (String)duty); - if(duty<1 && DEBUG_ssr) Serial.println("[SSR]: OFF"); + // Logger.println("[SSR] " + (String)out); + + if(!ssrDisabled){ + #ifdef ESP8266 + analogWrite( _ssrRelayPin, out); + #elif defined(ESP32) + Logger.println("[SSR] - " + (String)out); + analogWrite( _ssrRelayPin, out); + // dacWrite(_ssrRelayPin,out); + #endif + // if(duty == 0)ssr_off(); + // if(duty == 255)ssr_on(); + // else ssr_off(); // ENFORCE SAFETY + + // if(DEBUG_ssr) Logger.println("[SSR] " + (String)duty); + if(duty<1 && DEBUG_ssr) Logger.println("[SSR]: Duty OFF - " + (String)out); else{ - if(DEBUG_ssr) Serial.print("[SSR] ON"); - if(DEBUG_ssr) Serial.println( " - duty: " + (String)duty + " " + String( ( duty / 256.0 ) * 100) + "%" +" pow:" + String( round_f( power * 100 )) + "%" ); + if(DEBUG_ssr) Logger.print("[SSR] Duty ON"); + if(DEBUG_ssr) Logger.println( " - duty: " + (String)duty + " " + String( ( duty / 256.0 ) * 100) + "%" +" pow:" + String( round_f( power * 100 )) + "%" ); } } + } currentDuty = duty; } +void ssr_off(){ + if(_ssrRelayPin >= 0){ + Logger.println("[SSR] OFF"); + SetSSRFrequency(0); //working + analogWrite( _ssrRelayPin, invertDuty ? 255 : 0 ); // MUST use analogwrite if using shim lib + // digitalWrite(_ssrRelayPin, invertLOW ? LOW : HIGH); // @todo esp32 issue? must do analogwrite first + } +} + +void ssr_on(){ + if(_ssrRelayPin >= 0) { + Logger.println("[SSR] ON"); + SetSSRFrequency(255); // working + analogWrite( _ssrRelayPin, invertDuty ? 0: 255); + // digitalWrite(_ssrRelayPin, invertLOW ? HIGH : LOW); + } +} + void setSSR(int duty){ SetSSRFrequency(duty); } +void setSSRFreq(int duty){ + #ifdef ESP8266 + analogWriteFreq(duty); // min 100hz + #endif +} + float getSSRDuty(){ return currentDuty; } @@ -70,7 +115,50 @@ float getSSRPower(){ return ( currentDuty / 255.0 ) * 100; } -void ssrTest(){ +void ssr_resume(){ + Logger.println("[SSR] ssr_resume"); + if(_ssrRelayPin >= 0) setSSR(currentDuty); +} + +void disableSSR(bool disabled = true){ + Logger.println("[SSR] disable ssr"); + setSSR(0); + ssr_off(); + ssrDisabled = true; + // init safe state, lockdown + // pinMode(_ssrRelayPin,INPUT_PULLUP); +} + +void enableSSR(bool disabled = false){ + Logger.println("[SSR] enable ssr"); + setSSR(0); + ssr_off(); + ssrDisabled = false; + // init safe state + // pinMode(_ssrRelayPin,OUTPUT); // PINMODE BREAKS ANALOGWRITE LEDC CHANNEL + ssr_on(); + delay(500); // test pulse + ssr_off(); +} + +void toggleSSR(){ + ssrDisabled = !ssrDisabled; + if(!ssrDisabled) ssr_resume(); + else ssr_off(); +} + +void ssrTest(int speed){ + + ssrDisabled = false; + ssr_on(); + delay(1000); + ssr_off(); + delay(1000); + ssr_on(); + delay(1000); + ssr_off(); + delay(2000); + // Turn off the SSR - duty cycle of 0 SetSSRFrequency( 255 ); // test pulse delay(1000); @@ -79,6 +167,51 @@ void ssrTest(){ SetSSRFrequency( 255 ); // test pulse delay(1000); SetSSRFrequency( 0 ); + + for(int i=0;i<255;i++){ + SetSSRFrequency( i ); + delay(100); + } + + for(int i=0;i<255;i++){ + SetSSRFrequency( 255-i ); + delay(100); + } + + ssr_off(); + ssrDisabled = true; } +void ssrPing(int speed){ + Serial.println("[SSR] PING"); + + ssrDisabled = false; + ssr_off(); + ssr_off(); + + delay(500); + ssr_on(); + delay(speed*3); + ssr_off(); + delay(speed*3); + ssr_on(); + delay(speed*2); + ssr_off(); + delay(speed*2); + ssr_on(); + delay(speed); + + // for(int i=0;i<255;i+20){ + // SetSSRFrequency( i ); + // delay(100); + // } + + // for(int i=0;i<255;i+20){ + // SetSSRFrequency( 255-i ); + // delay(100); + // } + + ssr_off(); + ssrDisabled = true; +} #endif \ No newline at end of file diff --git a/storage.h b/storage.h new file mode 100644 index 0000000..cec61c1 --- /dev/null +++ b/storage.h @@ -0,0 +1,145 @@ +#ifndef storage_h +#define storage_h + +#include +#include + +void listDir(const char * dirname) { + Serial.printf("Listing directory: %s\n", dirname); + + Dir root = LittleFS.openDir(dirname); + + while (root.next()) { + File file = root.openFile("r"); + Serial.print(" FILE: "); + Serial.print(root.fileName()); + Serial.print(" SIZE: "); + Serial.print(file.size()); + time_t cr = file.getCreationTime(); + time_t lw = file.getLastWrite(); + file.close(); + struct tm * tmstruct = localtime(&cr); + Serial.printf(" CREATION: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + tmstruct = localtime(&lw); + Serial.printf(" LAST WRITE: %d-%02d-%02d %02d:%02d:%02d\n", (tmstruct->tm_year) + 1900, (tmstruct->tm_mon) + 1, tmstruct->tm_mday, tmstruct->tm_hour, tmstruct->tm_min, tmstruct->tm_sec); + } +} + + +void readFile(const char * path) { + Serial.printf("Reading file: %s\n", path); + + File file = LittleFS.open(path, "r"); + if (!file) { + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while (file.available()) { + Serial.write(file.read()); + } + file.close(); +} + +void writeFile(const char * path, const char * message) { + Serial.printf("Writing file: %s\n", path); + + File file = LittleFS.open(path, "w"); + if (!file) { + Serial.println("Failed to open file for writing"); + return; + } + if (file.print(message)) { + Serial.println("File written"); + } else { + Serial.println("Write failed"); + } + delay(2000); // Make sure the CREATE and LASTWRITE times are different + file.close(); +} + +void appendFile(const char * path, const char * message) { + Serial.printf("Appending to file: %s\n", path); + + File file = LittleFS.open(path, "a"); + if (!file) { + Serial.println("Failed to open file for appending"); + return; + } + if (file.print(message)) { + Serial.println("Message appended"); + } else { + Serial.println("Append failed"); + } + file.close(); +} + +void renameFile(const char * path1, const char * path2) { + Serial.printf("Renaming file %s to %s\n", path1, path2); + if (LittleFS.rename(path1, path2)) { + Serial.println("File renamed"); + } else { + Serial.println("Rename failed"); + } +} + +void deleteFile(const char * path) { + Serial.printf("Deleting file: %s\n", path); + if (LittleFS.remove(path)) { + Serial.println("File deleted"); + } else { + Serial.println("Delete failed"); + } +} + +void storage_test_basic(){ + if (!LittleFS.begin()) { + Serial.println("LittleFS mount failed"); + return; + } + const char * path = "/hello.txt"; + File file = LittleFS.open(path, "r"); + if (!file) { + Serial.println("Failed to open file for reading"); + return; + } + + Serial.print("Read from file: "); + while (file.available()) { + Serial.write(file.read()); + // read into buffer or use stream + } + file.close(); + LittleFS.end(); +} + +void storage_test_full(){ + Serial.println("Formatting LittleFS filesystem"); + LittleFS.format(); + Serial.println("Mount LittleFS"); + if (!LittleFS.begin()) { + Serial.println("LittleFS mount failed"); + return; + } + listDir("/"); + deleteFile("/hello.txt"); + writeFile("/hello.txt", "Hello "); + appendFile("/hello.txt", "World!\n"); + listDir("/"); + + Serial.println("The timestamp should be valid above"); + + Serial.println("Now unmount and remount and perform the same operation."); + Serial.println("Timestamp should be valid, data should be good."); + LittleFS.end(); + Serial.println("Now mount it"); + if (!LittleFS.begin()) { + Serial.println("LittleFS mount failed"); + return; + } + readFile("/hello.txt"); + listDir("/"); +} + +#endif \ No newline at end of file diff --git a/temp_logger.h b/temp_logger.h index defc236..0ca1532 100644 --- a/temp_logger.h +++ b/temp_logger.h @@ -2,8 +2,10 @@ #define temp_logger_h // #include +// #ifdef ESP32 +// #include +// #endif -#include #include #include @@ -11,9 +13,9 @@ // #include #include #include -#include +// #include #include -#include +// #include // #include #include @@ -32,12 +34,16 @@ BarGraph bar0; #define USENEOIND // use neopixel indicator #ifdef USENEOIND + #ifdef ESP32 + #define NEOINDPIN 19 + #else #define NEOINDPIN 2 + #endif #include #include #endif -// #define USENTC // use thermistor +#define USENTC // use thermistor #ifdef USENTC #include #endif @@ -64,7 +70,9 @@ BarGraph bar0; #define GFXX18pt &FreeSans18pt7b // #define GFXX18pt &FreeMono18pt7b -bool USEWIFI = true; // enabled wifi +int fpsmicros = 0; + +bool USEWIFI = true; // enabled wifi, NOT connect wifi Average fps(10); // init stats for avg (samples) @@ -129,7 +137,7 @@ int SCREENHEIGHT = 240; // TFT_WIDTH int GRAPHHEIGHT = SCREENHEIGHT-(FOOTERH); //padding 200px int GRAPHWIDTH = SCREENWIDTH; -int graphInterval = 1000; // graph update rate ms +int graphInterval = 15000; // graph update rate ms TFT_eSprite spr = TFT_eSprite(&tft); @@ -495,17 +503,21 @@ uint8_t TITLETOPPAD = 4; // main title top padding // add getter for colors? + // 7 magenta + // 8 cyan + // 4 greenyellow + // void updateTempA(){ String str = TEMPA; // Serial.println("footer val1: " + str); if(DEBUG_BOX) tft.setTextColor(WHITE,DEBUG_HC1); - else tft.setTextColor(WHITE,HC1); + else tft.setTextColor(getLineColor(7,0),HC1); tft.setTextDatum(TL_DATUM); int lpad = 2; tft.setTextPadding(115); // drawDatumMarker(2,2); // tft.setFreeFont(AA_FONT_MED); // Must load the font first - lpad += tft.drawString(str,lpad,TITLETOPPAD,4); + lpad += tft.drawString(str+"`",lpad,TITLETOPPAD,4); // Serial.println(lpad); tft.setTextPadding(0); } @@ -514,13 +526,13 @@ void updateTempB(){ String str = TEMPB; // Serial.println("footer val1: " + str); if(DEBUG_BOX) tft.setTextColor(WHITE,DEBUG_HC1); - else tft.setTextColor(WHITE,HC1); + else tft.setTextColor(getLineColor(8,0),HC1); tft.setTextDatum(TL_DATUM); int lpad = 120; tft.setTextPadding(115); // drawDatumMarker(2,2); // tft.setFreeFont(AA_FONT_MED); // Must load the font first - lpad += tft.drawString(str,lpad,TITLETOPPAD,4); + lpad += tft.drawString(str+"`",lpad,TITLETOPPAD,4); // Serial.println(lpad); tft.setTextPadding(0); } @@ -529,13 +541,13 @@ void updateTempC(){ String str = TEMPC; // Serial.println("footer val1: " + str); if(DEBUG_BOX) tft.setTextColor(WHITE,DEBUG_HC1); - else tft.setTextColor(WHITE,HC1); - tft.setTextDatum(TL_DATUM); + else tft.setTextColor(getLineColor(4,0),HC1); + tft.setTextDatum(TR_DATUM); int rpad = 5; tft.setTextPadding(115); // drawDatumMarker(2,2); // tft.setFreeFont(AA_FONT_MED); // Must load the font first - rpad += tft.drawString(str,SCREENWIDTH-rpad,TITLETOPPAD,4); + rpad += tft.drawString(str+"`",SCREENWIDTH-rpad,TITLETOPPAD,4); // Serial.println(lpad); tft.setTextPadding(0); } @@ -543,7 +555,7 @@ void updateTitle(){ String str = TITLE; // Serial.println("footer val1: " + str); if(DEBUG_BOX) tft.setTextColor(WHITE,DEBUG_HC1); - else tft.setTextColor(WHITE,HC1); + else tft.setTextColor(getLineColor(4,0),HC1); tft.setTextDatum(TL_DATUM); int lpad = 2; tft.setTextPadding(115); @@ -832,7 +844,7 @@ void wifiIcon(bool enabled = true,bool connected = false){ #define ICON_CHR_WIFI_OVERB "*" #define ICON_CHR_FANA "\"" #define ICON_CHR_FANB "#" -#define ICON_CHR_FANOVERA"$" +#define ICON_CHR_FANOVERA "$" #define ICON_CHR_FANOVERB "%" #define ICON_CHR_HEAT "&" diff --git a/tft_graph.h b/tft_graph.h index 458a29e..56d9559 100644 --- a/tft_graph.h +++ b/tft_graph.h @@ -1149,27 +1149,27 @@ void tft_footer_val1(){ tft_set_footer_val2(); } -int fpsmicros = millis(); -char buffer [32]; - -void displayFPS(){ - // tft_footer_val1(); - return; - tft.setTextSize(2); - tft.setTextColor(WHITE,HC2); - tft.setCursor(TFT_WIDTH,TFT_HEIGHT-100); - // frames / sec = 1 / (sec / frame) - // tft.println((String)(1000/((micros()-fpsmicros)))); - // tft.println((String)(1000000/((micros()-fpsmicros)))); - // tft.print(" "); - sprintf (buffer, "%03u",(int)(1000/((millis()-fpsmicros)))); - // Serial.println((String)(1000/((millis()-fpsmicros)))); - // tft.println((String)(1000/(millis()-fpsmicros))); - tft.println(buffer); - // Serial.println(buffer); - // println(" FPS"); - fpsmicros = millis(); -} +// int fpsmicros = millis(); +// char buffer [32]; + +// void displayFPS(){ +// // tft_footer_val1(); +// return; +// tft.setTextSize(2); +// tft.setTextColor(WHITE,HC2); +// tft.setCursor(TFT_WIDTH,TFT_HEIGHT-100); +// // frames / sec = 1 / (sec / frame) +// // tft.println((String)(1000/((micros()-fpsmicros)))); +// // tft.println((String)(1000000/((micros()-fpsmicros)))); +// // tft.print(" "); +// sprintf (buffer, "%03u",(int)(1000/((millis()-fpsmicros)))); +// // Serial.println((String)(1000/((millis()-fpsmicros)))); +// // tft.println((String)(1000/(millis()-fpsmicros))); +// tft.println(buffer); +// // Serial.println(buffer); +// // println(" FPS"); +// fpsmicros = millis(); +// } // what is this note? lol // float smoothing = 0.9; // larger=more smoothing diff --git a/wifi_funcs.h b/wifi_funcs.h index a312c37..5a56d84 100644 --- a/wifi_funcs.h +++ b/wifi_funcs.h @@ -3,59 +3,223 @@ #include +#ifdef ESP8266 + #include + #include + #define WIFI_getChipId() ESP.getChipId() +#elif defined(ESP32) + #include + #include + #include + #include + #define WIFI_getChipId() (uint32_t)ESP.getEfuseMac() +#endif + // const char* hostname = "esp8266REFLOW"; +bool debug_wifi = true; + +bool rebootAfterDowntime = true; +long downtimeRestart = 1*60000; // millis +long downms = 0; + +uint8_t _lastrssiperc = 0; // store rssi + +/** IP to String? */ +String toStringIp(IPAddress ip) { + String res = ""; + for (int i = 0; i < 3; i++) { + res += String((ip >> (8 * i)) & 0xFF) + "."; + } + res += String(((ip >> 8 * 3)) & 0xFF); + return res; +} + +String WiFi_SSID(bool persistent) { + persistent = true; + #ifdef ESP8266 + struct station_config conf; + if(persistent) wifi_station_get_config_default(&conf); + else wifi_station_get_config(&conf); + + char tmp[33]; //ssid can be up to 32chars, => plus null term + memcpy(tmp, conf.ssid, sizeof(conf.ssid)); + tmp[32] = 0; //nullterm in case of 32 char ssid + return String(reinterpret_cast(tmp)); + + #elif defined(ESP32) + if(persistent){ + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + return String(reinterpret_cast(conf.sta.ssid)); + } + else { + if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ + return String(); + } + wifi_ap_record_t info; + if(!esp_wifi_sta_get_ap_info(&info)) { + return String(reinterpret_cast(info.ssid)); + } + return String(); + } + #endif +} + +String WiFi_psk(bool persistent) { + persistent = true; + #ifdef ESP8266 + struct station_config conf; + + if(persistent) wifi_station_get_config_default(&conf); + else wifi_station_get_config(&conf); + + char tmp[65]; //psk is 64 bytes hex => plus null term + memcpy(tmp, conf.password, sizeof(conf.password)); + tmp[64] = 0; //null term in case of 64 byte psk + return String(reinterpret_cast(tmp)); + + #elif defined(ESP32) + // only if wifi is init + if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ + return String(); + } + wifi_config_t conf; + esp_wifi_get_config(WIFI_IF_STA, &conf); + return String(reinterpret_cast(conf.sta.password)); + #endif +} + +bool wifiIsAutoConnect(){ + return WiFi_SSID(true) != ""; +} + +bool wifiIsConnected(){ + return WiFi.status() == WL_CONNECTED; +} + +void setWiFiFastConnect(){ + //fast scan + // set channel + // set bssid + // WiFi.begin(SSID,PASS,WiFi.channel(),WiFi.BSSID(),true); +} + +String getDeviecID(){ + String _wifissidprefix = "ESP"; + String hostString = String(WIFI_getChipId(),HEX); + hostString.toUpperCase(); + // char hostString[16] = {0}; + // sprintf(hostString, "%06X", ESP.getChipId()); + return _wifissidprefix + "_" + hostString; +} + +void setWiFiHostname(const char* hostname){ + // @todo add string templ + #ifdef ESP32 + WiFi.setHostname(hostname); + #else + MDNS.begin(hostname); + WiFi.hostname(hostname); + #endif +} + +String getHostname(){ + #ifdef ESP32 + return WiFi.getHostname(); // getHostName ( @todo return string or c.str?) + #else + return WiFi.hostname(); // getHostName + #endif +} + +void WiFi_print_sta(){ + if(wifiIsConnected()){ + Serial.println("[WIFI] CONNECTED"); + Serial.print("[WIFI] IP: "); + Serial.println(WiFi.localIP()); + Serial.print("[WIFI] HOST: "); + Serial.println(getHostname()); + Serial.print("[WIFI] BSSID: "); + Serial.println(WiFi.BSSIDstr()); + Serial.print("[WIFI] RSSI: "); + Serial.println(WiFi.RSSI()); + Serial.print("[WIFI] CHANNEL: "); + Serial.println(WiFi.channel()); + } else { + Serial.println("[WIFI] NOT CONNECTED"); + } +} // enable wifi sta // disable sleep // timeout connect // set hostname ? -void init_WiFi(int timeout = 10000){ +void init_WiFi(int timeout){ + // if(wifiIsConnected()){ + // WiFi_print_sta(); + // return; + // } + unsigned long start = millis(); + Serial.println("[WIFI] mode STA"); WiFi.mode(WIFI_STA); + if(debug_wifi) WiFi.printDiag(Serial); #ifdef ESP8266 WiFi.setSleepMode(WIFI_NONE_SLEEP); #elif defined(ESP32) // btStop(); WiFi.setSleep(false); #endif - +// // WiFi.hostname(hostname); - unsigned long start = millis(); + // if(wifiIsAutoConnect) WiFi.begin(); + // esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_11B| WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR); + WiFi.begin(SSID,PASS); if(timeout > 0){ - Serial.println("[WIFI] Connecting to wifi... [" + (String)timeout + " ms]\n"); + // use local timer loop + if(debug_wifi) Serial.println("[WIFI] Connecting to wifi, wait for timeout... [" + (String)timeout + " ms]\n"); while((WiFi.status() != WL_CONNECTED) && (millis()-start < timeout)){ - Serial.print("."); + if(debug_wifi) Serial.print("."); delay(100); } } else { - Serial.println("[WIFI] Connecting to wifi, waiting..... "); - while(WiFi.waitForConnectResult() != WL_CONNECTED){ - Serial.print("."); - delay(100); - } + // waitForConnecrtResult default 60000 + if(debug_wifi) Serial.println("[WIFI] Connecting to wifi, waitForConnectResult waiting..... "); + uint8_t status = WiFi.waitForConnectResult(); + // while(status() != WL_CONNECTED){ + // Serial.print("."); + // delay(500); + Serial.println((String)WiFi.status()); + // } } - Serial.println(""); + if(debug_wifi) Serial.println(""); - if(WiFi.status() == WL_CONNECTED){ - Serial.println("[WIFI] CONNECTED"); - Serial.print("[WIFI] IP: "); - Serial.println(WiFi.localIP()); - Serial.print("[WIFI] HOST: "); - Serial.println(WiFi.getHostname()); + if(wifiIsConnected()){ + setWiFiFastConnect(); + Serial.println("[WIFI] connected in " + (String)(millis()-start/1000) + " ms"); + if(debug_wifi) WiFi_print_sta(); } else{ Serial.println("[ERROR] WIFI CONNECT FAILED"); - Serial.println("[WIFI] waited for " + (String)(millis()-start/1000) + "seconds"); + Serial.println("[WIFI] waited for " + (String)(millis()-start/1000) + " ms"); + // delay(1000); + // WiFi.begin(SSID,PASS); } delay(500); } -int getRSSIasQuality() { - int RSSI = WiFi.RSSI(); - int quality = 0; +void init_WiFi(){ + init_WiFi(0); +} + +void init_WiFi_saved(){ + WiFi.begin(); +} + +uint8_t getRSSIasQuality(int8_t RSSI) { + uint8_t quality = 0; if (RSSI <= -100) { quality = 0; @@ -64,31 +228,72 @@ int getRSSIasQuality() { } else { quality = 2 * (RSSI + 100); } + _lastrssiperc = quality; return quality; } -void checkWifi(){ +uint8_t getRSSIasQuality() { + return getRSSIasQuality(WiFi.RSSI()); +} + +/** + * [checkWifi description] + * @param restart [description] + */ + +void checkWifi(bool recon = true, bool restart = false){ + Serial.println("[TASK] checkWiFi"); if(WiFi.status() != WL_CONNECTED ){ + if(downms == 0) downms = millis(); + if(millis() > downms + downtimeRestart){ + if(restart){ + // reboot + #ifdef USENEOIND + indSetColor(np_red); + #endif + Serial.println("[ERROR] wifi not found, rebooting after timeout"); + Serial.flush(); + delay(1000); + ESP.restart(); + } + else{ + // reconnect + #ifdef USENEOIND + indSetColor(np_red); + #endif + Serial.println("[WIFI] WiFi is Disconnected for " + (String)(millis()-downms)); + downms = millis(); + if(recon) WiFi.reconnect(); + } + } + } + else { + _lastrssiperc = getRSSIasQuality(); + if(debug_wifi){ + Serial.println("[WIFI] WiFi is CONNECTED"); + Serial.println("[WIFI] RSSI: "+(String)_lastrssiperc); + } #ifdef USENEOIND - indSetColor(255,0,0); - #endif - Serial.println("[WIFI] WiFi Disconnected"); - WiFi.reconnect(); - } else { - Serial.println("[WIFI] RSSI: "+(String)getRSSIasQuality()); - #ifdef USENEOIND - indSetColor(0,255,0); + indSetColor(np_green); #endif } } +void checkWifi(){ + checkWifi(true,false); +} + void enableWiFi(){ WiFi.mode(WIFI_STA); - init_WiFi(); + init_WiFi(0); } void disableWiFi(){ WiFi.mode(WIFI_OFF); + #ifdef ESP32 + WiFi.mode( WIFI_MODE_NULL ); + btStop(); + #endif } // uint32_t ResetReason(void) @@ -123,7 +328,7 @@ void disableWiFi(){ // } else { // strcpy_P(buff, PSTR("Unknown")); - +// #ifdef ESP32 // String ESP32GetResetReason(uint32_t cpu_no) { // // tools\sdk\include\esp32\rom\rtc.h // switch (rtc_get_reset_reason( (RESET_REASON) cpu_no)) { @@ -145,6 +350,30 @@ void disableWiFi(){ // default : return F("NO_MEAN"); // 0 // } // } +// #endif + +// void esp32_resetreason(RESET_REASON reason) +// { +// switch ( reason) +// { +// case 1 : Serial.println ("Vbat power on reset");break; +// case 3 : Serial.println ("Software reset digital core");break; +// case 4 : Serial.println ("Legacy watch dog reset digital core");break; +// case 5 : Serial.println ("Deep Sleep reset digital core");break; +// case 6 : Serial.println ("Reset by SLC module, reset digital core");break; +// case 7 : Serial.println ("Timer Group0 Watch dog reset digital core");break; +// case 8 : Serial.println ("Timer Group1 Watch dog reset digital core");break; +// case 9 : Serial.println ("RTC Watch dog Reset digital core");break; +// case 10 : Serial.println ("Instrusion tested to reset CPU");break; +// case 11 : Serial.println ("Time Group reset CPU");break; +// case 12 : Serial.println ("Software reset CPU");break; +// case 13 : Serial.println ("RTC Watch dog Reset CPU");break; +// case 14 : Serial.println ("for APP CPU, reseted by PRO CPU");break; +// case 15 : Serial.println ("Reset when the vdd voltage is not stable");break; +// case 16 : Serial.println ("RTC Watch dog reset digital core and rtc module");break; +// default : Serial.println ("NO_MEAN"); +// } +// } // String ESP_getResetReason(void) { // return ESP32GetResetReason(0); // CPU 0 @@ -158,60 +387,158 @@ void disableWiFi(){ // if (SW_RESET == reason) { return REASON_EXT_SYS_RST; } // } -bool wifiIsConnected(){ - return WiFi.status() == WL_CONNECTED; -} + // esp_wifi_get_mac((wifi_interface_t)interface, mac); + // sprintf(winstance, "%s [%02x:%02x:%02x:%02x:%02x:%02x]", _hostname.c_str(), mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); -String WiFi_SSID(bool persistent) { + // esp_wifi_get_mac((wifi_interface_t)WIFI_IF_STA, eth_mac); + // snprintf(default_hostname, 32, "%s%02X%02X%02X", CONFIG_IDF_TARGET "-", eth_mac[3], eth_mac[4], eth_mac[5]); - #ifdef ESP8266 - struct station_config conf; - if(persistent) wifi_station_get_config_default(&conf); - else wifi_station_get_config(&conf); - char tmp[33]; //ssid can be up to 32chars, => plus null term - memcpy(tmp, conf.ssid, sizeof(conf.ssid)); - tmp[32] = 0; //nullterm in case of 32 char ssid - return String(reinterpret_cast(tmp)); - - #elif defined(ESP32) - if(persistent){ - wifi_config_t conf; - esp_wifi_get_config(WIFI_IF_STA, &conf); - return String(reinterpret_cast(conf.sta.ssid)); - } - else { - if(WiFiGenericClass::getMode() == WIFI_MODE_NULL){ - return String(); - } - wifi_ap_record_t info; - if(!esp_wifi_sta_get_ap_info(&info)) { - return String(reinterpret_cast(info.ssid)); - } - return String(); - } - #endif -} +// const char * const WIFI_STA_STATUS[] PROGMEM +// { +// "WL_IDLE_STATUS", // 0 STATION_IDLE +// "WL_NO_SSID_AVAIL", // 1 STATION_NO_AP_FOUND +// "WL_SCAN_COMPLETED", // 2 +// "WL_CONNECTED", // 3 STATION_GOT_IP +// "WL_CONNECT_FAILED", // 4 STATION_CONNECT_FAIL, STATION_WRONG_PASSWORD(NI) +// "WL_CONNECTION_LOST", // 5 +// "WL_DISCONNECTED", // 6 +// "WL_STATION_WRONG_PASSWORD" // 7 KLUDGE +// }; -bool wifiIsAutoConnect(){ - return WiFi_SSID(true) != ""; +// #ifdef ESP32 +// const char * const AUTH_MODE_NAMES[] PROGMEM +// { +// "OPEN", +// "WEP", +// "WPA_PSK", +// "WPA2_PSK", +// "WPA_WPA2_PSK", +// "WPA2_ENTERPRISE", +// "MAX" +// }; +// #elif defined(ESP8266) +// const char * const AUTH_MODE_NAMES[] PROGMEM +// { +// "", +// "", +// "WPA_PSK", // 2 ENC_TYPE_TKIP +// "", +// "WPA2_PSK", // 4 ENC_TYPE_CCMP +// "WEP", // 5 ENC_TYPE_WEP +// "", +// "OPEN", //7 ENC_TYPE_NONE +// "WPA_WPA2_PSK", // 8 ENC_TYPE_AUTO +// }; +// #endif + +// const char* const WIFI_MODES[] PROGMEM = { "NULL", "STA", "AP", "STA+AP" }; +// typedef enum { +// NO_MEAN = 0, +// POWERON_RESET = 1, /**<1, Vbat power on reset*/ +// RTC_SW_SYS_RESET = 3, /**<3, Software reset digital core*/ +// DEEPSLEEP_RESET = 5, /**<5, Deep Sleep reset digital core*/ +// TG0WDT_SYS_RESET = 7, /**<7, Timer Group0 Watch dog reset digital core*/ +// TG1WDT_SYS_RESET = 8, /**<8, Timer Group1 Watch dog reset digital core*/ +// RTCWDT_SYS_RESET = 9, /**<9, RTC Watch dog Reset digital core*/ +// INTRUSION_RESET = 10, /**<10, Instrusion tested to reset CPU*/ +// TG0WDT_CPU_RESET = 11, /**<11, Time Group0 reset CPU*/ +// RTC_SW_CPU_RESET = 12, /**<12, Software reset CPU*/ +// RTCWDT_CPU_RESET = 13, /**<13, RTC Watch dog Reset CPU*/ +// RTCWDT_BROWN_OUT_RESET = 15, /**<15, Reset when the vdd voltage is not stable*/ +// RTCWDT_RTC_RESET = 16, /**<16, RTC Watch dog reset digital core and rtc module*/ +// TG1WDT_CPU_RESET = 17, /**<17, Time Group1 reset CPU*/ +// SUPER_WDT_RESET = 18, /**<18, super watchdog reset digital core and rtc module*/ +// GLITCH_RTC_RESET = 19, /**<19, glitch reset digital core and rtc module*/ +// } RESET_REASON; + +const char * const RESET_REASON_STR[] PROGMEM +{ + "NO_MEAN" , + "POWERON_RESET" , /**<1, Vbat power on reset*/ + "", + "RTC_SW_SYS_RESET" , /**<3, Software reset digital core*/ + "", + "DEEPSLEEP_RESET" , /**<5, Deep Sleep reset digital core*/ + "", + "TG0WDT_SYS_RESET" , /**<7, Timer Group0 Watch dog reset digital core*/ + "TG1WDT_SYS_RESET" , /**<8, Timer Group1 Watch dog reset digital core*/ + "RTCWDT_SYS_RESET" , /**<9, RTC Watch dog Reset digital core*/ + "INTRUSION_RESET" , /**<10, Instrusion tested to reset CPU*/ + "TG0WDT_CPU_RESET" , /**<11, Time Group0 reset CPU*/ + "RTC_SW_CPU_RESET" , /**<12, Software reset CPU*/ + "RTCWDT_CPU_RESET" , /**<13, RTC Watch dog Reset CPU*/ + "", + "RTCWDT_BROWN_OUT_RESET" , /**<15, Reset when the vdd voltage is not stable*/ + "RTCWDT_RTC_RESET" , /**<16, RTC Watch dog reset digital core and rtc module*/ + "TG1WDT_CPU_RESET" , /**<17, Time Group1 reset CPU*/ + "SUPER_WDT_RESET" , /**<18, super watchdog reset digital core and rtc module*/ + "GLITCH_RTC_RESET" /**<19, glitch reset digital core and rtc module*/ +}; + +// typedef enum { +// NO_MEAN = "NO_MEAN", +// POWERON_RESET = "Vbat power on reset", +// RTC_SW_SYS_RESET = "Software reset digital core", +// DEEPSLEEP_RESET = "Deep Sleep reset digital core", +// TG0WDT_SYS_RESET = "Timer Group0 Watch dog reset digital core", +// TG1WDT_SYS_RESET = "Timer Group1 Watch dog reset digital core", +// RTCWDT_SYS_RESET = "RTC Watch dog Reset digital core", +// INTRUSION_RESET = "Instrusion tested to reset CPU", +// TG0WDT_CPU_RESET = "Time Group0 reset CPU", +// RTC_SW_CPU_RESET = "Software reset CPU", +// RTCWDT_CPU_RESET = "RTC Watch dog Reset CPU", +// RTCWDT_BROWN_OUT_RESET = "Reset when the vdd voltage is not stable", +// RTCWDT_RTC_RESET = "RTC Watch dog reset digital core and rtc module", +// TG1WDT_CPU_RESET = "Time Group1 reset CPU", +// SUPER_WDT_RESET = "super watchdog reset digital core and rtc module", +// GLITCH_RTC_RESET = "glitch reset digital core and rtc module" +// } RESET_REASON_STR_v; + + +void verbose_print_reset_reason(int reason) +{ + switch ( reason) + { + case 1 : Serial.println ("Vbat power on reset");break; + case 3 : Serial.println ("Software reset digital core");break; + case 4 : Serial.println ("Legacy watch dog reset digital core");break; + case 5 : Serial.println ("Deep Sleep reset digital core");break; + case 6 : Serial.println ("Reset by SLC module, reset digital core");break; + case 7 : Serial.println ("Timer Group0 Watch dog reset digital core");break; + case 8 : Serial.println ("Timer Group1 Watch dog reset digital core");break; + case 9 : Serial.println ("RTC Watch dog Reset digital core");break; + case 10 : Serial.println ("Instrusion tested to reset CPU");break; + case 11 : Serial.println ("Time Group reset CPU");break; + case 12 : Serial.println ("Software reset CPU");break; + case 13 : Serial.println ("RTC Watch dog Reset CPU");break; + case 14 : Serial.println ("for APP CPU, reseted by PRO CPU");break; + case 15 : Serial.println ("Reset when the vdd voltage is not stable");break; + case 16 : Serial.println ("RTC Watch dog reset digital core and rtc module");break; + default : Serial.println ("NO_MEAN"); + } } -String getResetReason(){ +// @todo +String getResetReason(uint8_t cpu = 0){ int reason; #ifdef ESP8266 return ESP.getResetReason(); - #elif defined(ESP32) && defined(_ROM_RTC_H_) - // requires #include - p = FPSTR(HTTP_INFO_lastreset); - for(int i=0;i<2;i++){ - int reason = rtc_get_reset_reason(i); - return (String)reason; - // switch (reason) - // { - // } - } + #elif defined(ESP32) + // && defined(_ROM_RTC_H_) + // requires #include + Serial.print("[RESET]");verbose_print_reset_reason(rtc_get_reset_reason(cpu)); + return RESET_REASON_STR[rtc_get_reset_reason(cpu)]; + // return "NA"; + #else + return (String)rtc_get_reset_reason(cpu) + " - UNKNOWN"; #endif } -#endif \ No newline at end of file +void processWiFi(){ + #ifdef ESP8266 + MDNS.update(); + #endif +} + +#endif \ No newline at end of file