Project showcase
CronoThermostat PRO V2

CronoThermostat PRO V2 © GPL3+

Heating system control for system section solenoid valves with WEBServer services for setting parameters and view state.

  • 108 views
  • 0 comments
  • 1 respect

Components and supplies

Apps and online services

About this project

Follow my previous project here I want to upgrade the difficult, so I use other components and develop a WEB server to access parametric settings.

Here other view from little OLED interface.

MAIN functionalities:

  • Idle display temperature and state of the plant
  • Force state plant ON or OFF for many hours
  • NTP date and time
  • Switch plant ON/OFF
  • Preset of temperature offset
  • 4 different day program
  • 7day week 4program assignment
  • WEB server for access all parameters

Code

CT2_FA.inoC/C++
/*
   CT2_FA cronoTermostat V2
   by Fabrizio Allevi
   fabrizio . allevi @ tiscali . it
*/

#include "main.h"

// globals
int smLevel = 0;
String sDays[MAX_DAYS] = { "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" };
String sMonth[12] = { "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic" };
int smValue = 0;
bool bProgram = false;
int nProg = 0;
int arrayDT[5];

void showDateTimePage(bool bGet = false);
void idlePage(float fTemp);

int smCursor = 0;
unsigned long msIdle = millis();
unsigned long msTemp = millis();
unsigned long msScheduler = millis();
unsigned long msLast = millis();
unsigned long msDimmer = millis();
bool bIdleState = true;
float lastTemp = 0.0f;
bool bForce=false;
long lastOp=0;

void setup() {
  // Open serial communications and wait for port to open:
  if (DEBUG) {
    Serial.begin(9600);
    while (!Serial) {
      delay(1000); // wait for serial port to connect. Needed for native USB port only
    }
  }
  pinMode(CALDAIA, OUTPUT);
  digitalWrite(CALDAIA, HIGH);  // spengo rele
  initKnob();
  initOled();
  initTempService();
  lowDimmer();
  settingsPage('#');
  initWifiService();
  if(DEBUG)  
    Serial.println("setup terminated!");
  lastOp=millis()-10000;
}

long lastUpd=0;
int aux=0;
int page=0; //0=idle 1=force 2=prog
bool bModify=false;
void loop() {
  runWifiService(lastTemp);
  long nowTime=millis();
  int dir = getDir();
  bool sw = getSwitch();
  if(!bModify) {  // volta pagina
    if(dir) {
      lastOp=nowTime;
    }
    else if(nowTime>lastOp+10000) {
      aux=0;
    }
    aux+=dir;
    if(aux<0)
      aux=0;
    if(aux>12)
      aux=12;
    page=aux/4;
    // pages handling
    if(page==0) { // idle page
      if(nowTime>lastUpd+5000) {
        lastTemp = readTemp();
        idlePage(lastTemp);
        lastUpd=nowTime;
        scheduler(lastTemp);
      }
    }
    else if(page==1) {  // force page
      forcePage(sto.forceData.hForce);
    }
    else if(page==2) {  // program page
      programPage();
    }
    else if(page==3) {  // settings page
      settingsPage(isOnAir?'@':'#');
    }
    if(sw && (page==1 || page==3)) {
      bModify=true;
      lastOp=nowTime;
      if(page==1)
        aux=sto.forceData.hForce*4;
      else if(page==3)
        settingsPage('R');
    }
  }
  else {  // modifica
    if(nowTime<lastOp+10000) {
      if(page==1) {
        if(dir) {
          aux+=dir;
          lastOp=nowTime;
        }
        else {
          int hf=aux/4;
          forcePage(hf);
          if(sw && hf!=sto.forceData.hForce) {
            sto.forceData.hForce=hf;
            sto.forceData.tFin=now()+sto.forceData.hForce*3600; 
            page=0;
            aux=0;
            bModify=false;
          }
        }
      }
      else if(page==3) {
        if(sw) {
          settingsPage('>');
          delay(1000);
          NVIC_SystemReset(); // system reset
        }
      }
    }
    else {
      page=0;
      aux=0;
      bModify=false;
    }
  }
}

void idlePage(float fTemp) {
  char text[100];
  sprintf(text, "%.1f", fTemp);
  clearOled();
  drawbitmap(100, 10);
  printOled(text, 20, 8, 3, true);
}

void forcePage(int hour) {
  char text[100];
  clearOled();
  sprintf(text, "Force for....\n");
  printOled(text, 0, 0, 1, false);
  sprintf(text, "%d hour!", hour);
  printOled(text, 0, 10, 2, true);
}

void programPage() {
  char text[100];
  clearOled();
  int wd=weekday()-1;
  sprintf(text, "%s %d %s %d %.02d:%.02d\n", sDays[wd].c_str(), day(), sMonth[month()-1].c_str(), year(), hour(), minute());
  printOled(text, 4, 0, 1, false);
  int prg=sto.weekProg[wd];
  int i1, i2=-1;
  int tp, tn=hour()*60+minute();
  do {
    i2++;
    tp=(sto.progs[prg].HM[i2]>>8)*60+(sto.progs[prg].HM[i2]&0xFF);
  } while(tp<tn && i2<6);
  i1=i2-1;
  sprintf(text, "__%.1f   %.1f__\n", ((float)(sto.progs[prg].T[i1]))/10.0f, ((float)(sto.progs[prg].T[i2]))/10.0f);
  printOled(text, 18, 14, 1, false);
  sprintf(text, "__%.02d:%.02d %.02d:%.02d__\n", sto.progs[prg].HM[i1]>>8, sto.progs[prg].HM[i1]&0xFF, sto.progs[prg].HM[i2]>>8, sto.progs[prg].HM[i2]&0xFF);
  printOled(text, 18, 24, 1, true);
}

void settingsPage(char c) {
  char text[100];
  clearOled();
  sprintf(text, "ipAddr: %s\n", ipAddr.c_str());
  printOled(text, 0, 0, 1, false);
  if(c=='R') {
    sprintf(text, "click knob for Reset!");
    printOled(text, 0, 10, 1, false);
  }
  if(c=='>') {
    sprintf(text, "reset in progress!");
    printOled(text, 0, 10, 1, false);
  }
  sprintf(text, "%c", c);
  printOled(text, 120, 25, 1, true);
}
knob.cppC/C++
/*
   gestione Encoder rotativo
   by Fabrizio Allevi
   fabrizio . allevi @ tiscali . it
*/

#include <Encoder.h>
#include "main.h"
#define PIN_SWITCH 7

Encoder knob(5, 6);
void switchState();
long oldPosition;

void initKnob() {
  pinMode(PIN_SWITCH, INPUT_PULLUP); // switch
  attachInterrupt(digitalPinToInterrupt(PIN_SWITCH), switchState, FALLING);
  oldPosition=knob.read();
}

long getPos() {
  long newPosition=knob.read();
  if(newPosition!=oldPosition) {
    if(DEBUG) {
        Serial.println(newPosition);
    }
    oldPosition=newPosition;
  }
  return newPosition;
}

int getDelta() {
  long newPosition=knob.read();
  int delta=newPosition-oldPosition;
  oldPosition=newPosition;
  if(delta!=0 && DEBUG) {
      Serial.println(delta);
  }
  return delta;
}

int getDir() {
  int dir=0;
  long newPosition=knob.read();
  if(oldPosition>newPosition)
    dir=-1;
  else if(oldPosition<newPosition)
    dir=1;
  oldPosition=newPosition;
  return dir;
}

long lLast=millis();
bool bOn=false;
bool getSwitch() {
  if(bOn) {
    bOn=false;
    if(DEBUG)
        Serial.println("switch ON!");
    return true;
  }
  return false;
}

void switchState() {
  long lNow=millis();
  if(!bOn && lNow>lLast+1000)
    bOn=true, lLast=lNow;
}
main.hC/C++
/*
 * main include file
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */
 
// defines
//#define DEBUG true
#define DEBUG false

#define CALDAIA 4 // digital pin out 4
#define LEVEL_ZERO 0
#define LEVEL_PROGRAMS 1
#define LEVEL_DAYS 2
#define LEVEL_DATETIME 3
#define LEVEL_OFSTEMP 4
#define LEVEL_FORCE 5
#define LEVEL_OFF 6
#define MAX_MENU 7
#define MAX_PROGS 4
#define MAX_DAYS 7
#define MAX_SEQ 6

#include <Arduino.h>
#include <TimeLib.h>

// wifi + store
void initWifiService();
void runWifiService(float fTemp);
void saveDataFlash();
// temp
void initTempService();
float readTemp();
// knob
void initKnob();
long getPos();
int getDelta();
int getDir();
bool getSwitch();
// oled
void printOled(const char *text, int posx, int posy, int size, bool bShow);
void setCursorOled(int row, int col);
void initOled();
void clearOled();
void blinkOled(bool bOn);
void scrollOled(bool bOn);
void lowDimmer();
void normalDimmer();
void changeDimmer();
void setDimmer(int d);
void drawbitmap(int posx, int posy);
// scheduler
void scheduler(float tempNow);

// globals 
struct stForce {
  int hForce;
  unsigned long tFin;
  int ofsTemp;
  int maxTemp;
  bool bOFF;
};
struct stProgram {
  int T[MAX_SEQ];  // in decimi di grado
  int HM[MAX_SEQ]; // hhmm nei 16bit hh=partealta mm=partebassa
};
struct stStorage {
  bool bValue;	
  stProgram progs[MAX_PROGS];
  int weekProg[MAX_DAYS];
  stForce forceData;
};
extern stStorage sto;
extern bool bFire;
extern String ipAddr;
extern bool isOnAir;
oledService.cppC/C++
/*
 * gestione OLED per programma CT2_FA
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "main.h"

// oled init----------------------------------------------------------------
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

#define LOGO_HEIGHT   16
#define LOGO_WIDTH    16
static const unsigned char PROGMEM fire_bmp[] =
{ B00000001, B00000000,
  B00000001, B10000000,
  B00000011, B11100000,
  B00000111, B00110000,
  B00001110, B00011000,
  B00011100, B00001100,
  B00111000, B00000110,
  B01110000, B00000011,
  B11100000, B10000011,
  B11100000, B01000011,
  B11100000, B00100011,
  B11000010, B00100011,
  B01100100, B00100011,
  B00100010, B01000110,
  B00010001, B10001000,
  B00001000, B00010000 };
static const unsigned char PROGMEM off_bmp[] =
{ B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B11000001, B10000011,
  B11000001, B10000011,
  B11111111, B11111111 };

void initOled() {
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x32
    if(DEBUG)
      Serial.println(F("SSD1306 allocation failed"));
    while (true);
  }
  // Clear the buffer
  display.clearDisplay();
  display.display();
}


int dimmer=0;
int delta=1;
void changeDimmer() {
  dimmer+=delta;
  if(dimmer>=2)
    delta=-1;
  else if(dimmer<=0)
    delta=1;
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(dimmer);
}

void setDimmer(int d) {
  if(d>=0x8F)
    d=0x8F;
  else if(d<0)
    d=0;
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(d);
}

void lowDimmer() {
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(0x01);
}

void normalDimmer() {
  display.ssd1306_command(SSD1306_SETCONTRAST);
  display.ssd1306_command(0x20);
}

void printOled(const char *text, int posx, int posy, int size, bool bShow) {  // 6x8 12x16 18x24
  display.setTextSize(size);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(posx,posy);
  display.println(text);
  if(bShow)
    display.display();
}

void setCursorOled(int row, int col) {
  display.setCursor(row*9,col*7);
}

void clearOled() {
  display.clearDisplay();
}

void blinkOled(bool bOn) {
}

void scrollOled(bool bOn) {
  if(bOn)
    display.startscrollright(0x00, 0x0F);
  else 
    display.stopscroll();
}

void drawbitmap(int posx, int posy) {
  //display.drawBitmap((display.width()-LOGO_WIDTH )/2, (display.height()-LOGO_HEIGHT)/2, fire_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  if(bFire)
    display.drawBitmap(posx, posy, fire_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
  else
    display.drawBitmap(posx, posy, off_bmp, LOGO_WIDTH, LOGO_HEIGHT, 1);
}
scheduler.cppC/C++
/*
   scheduler per programma CT2_FA
   by Fabrizio Allevi
   fabrizio . allevi @ tiscali . it
*/
#include <Wire.h>
#include "main.h"

bool bFire = false;
void scheduler(float tempNow) {
  int hh = hour();
  int minuteNow = hh * 60 + minute();
  int idProg = sto.weekProg[weekday()-1];
  if (DEBUG) {
    Serial.print("minuteNow=");
    Serial.print(minuteNow);
    Serial.print(" idProg=");
    Serial.println(idProg);
  }
  // controllo force functionality
  if (sto.forceData.hForce) {
    if (sto.forceData.tFin > now()) {
      if (sto.forceData.hForce>0 && hh>7 && hh<23 && tempNow<((float)(sto.forceData.maxTemp))/10.0f) // forza ma non di notte e se supero maxtemp
        bFire = true;
      else
        bFire = false;
      if (DEBUG) {
        Serial.print("forceFor=");
        Serial.print(sto.forceData.hForce);
        Serial.println(" hour");
      }
    }
    else {
      sto.forceData.hForce = 0;
      sto.forceData.tFin = 0;
      //saveData((byte*)&forceData, sizeof(forceData), EEPROM_OFSF);
    }
  }
  else {
    // check sequences
    for (int seq = 0; seq < MAX_SEQ - 1; seq++) {
      int minI = (sto.progs[idProg].HM[seq] >> 8) * 60 + (sto.progs[idProg].HM[seq] & 0xFF);
      int minF = (sto.progs[idProg].HM[seq + 1] >> 8) * 60 + (sto.progs[idProg].HM[seq + 1] & 0xFF);
      if (minI <= minuteNow && (minuteNow < minF || minF == 0)) { // trovata la seq in corso
        float setPtemp = sto.progs[idProg].T[seq]; // setpoint di temperatura da tenere in questa sequenza
        setPtemp /= 10.0;
        if (DEBUG) {
          Serial.print("seq=");
          Serial.print(seq);
          Serial.print(" minI=");
          Serial.print(minI);
          Serial.print(" minF=");
          Serial.print(minF);
          Serial.print(" temp=");
          Serial.println(setPtemp);
        }
        if ((!bFire && tempNow < setPtemp) || (bFire && tempNow < (setPtemp + 0.15f)))
          bFire = true;
        else
          bFire = false;
        break;
      }
    }
  }
  // caldaia
  if (bFire && !sto.forceData.bOFF) {
    digitalWrite(CALDAIA, LOW);
  }
  else {
    digitalWrite(CALDAIA, HIGH);
  }
}
tempService.cppC/C++
/*
   TempSensor: gestione lettura della temperatura da sensore MCP9808
   by Fabrizio Allevi
   fabrizio . allevi @ tiscali . it
*/

#include <Adafruit_MCP9808.h>
#include "main.h"

Adafruit_MCP9808 tempSensor = Adafruit_MCP9808();

void initTempService() {
  if (!tempSensor.begin(0x18) && DEBUG)
    Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
  tempSensor.setResolution(3); // sets the resolution 0-0.5C-30ms | 1-0.25C-65ms | 2-0.125C-130ms | 3-0.0625C-250ms
}


float readTemp() {
  tempSensor.wake();   // wake up, ready to read!
  float ntr=tempSensor.readTempC();
  float ofs=(float)sto.forceData.ofsTemp;
  ofs/=10.0f;
  float nto=ntr+ofs;
  if (DEBUG) {
    Serial.print("TempRead: ");
    Serial.print(ntr, 4);
    Serial.print("C - TempOfs: ");
    Serial.print(nto, 4);
    Serial.println("C");
  }
  tempSensor.shutdown_wake(1); // shutdown MSP9808 - power consumption ~0.1 mikro Ampere, stops temperature sampling
  return nto;
}
wifiService.cpp PART1C/C++
/*
   wifiService: gestione wifi
   by Fabrizio Allevi
   fabrizio . allevi @ tiscali . it
*/

#include <SPI.h>
#include <WiFiNINA.h>
#include "main.h"

int status = WL_IDLE_STATUS;
#include "secret.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

unsigned int localPort = 2390;      // local port to listen for UDP packets
//IPAddress timeServer(129, 6, 15, 28); // time.nist.gov NTP server
IPAddress timeServer(193,204,114,105);  // time.inrim.it
const int NTP_PACKET_SIZE = 48; // NTP time stamp is in the first 48 bytes of the message
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
// exported
String ipAddr="?.?.?.?";
bool isOnAir=false;
void checkConnection(long msNow);

WiFiServer server(80);  // HTTP service

// storage
stStorage preSto =  {true,
                    {{{ 200, 190, 200, 190, 200, 190 }, { 0x071E, 0x091E, 0x0B00, 0x0D00, 0x0F00, 0x1700 }},
                    {{ 200, 190, 200, 190, 190, 190 }, { 0x071E, 0x091E, 0x0F00, 0x1700, 0x0000, 0x0000 }},
                    {{ 200, 190, 200, 190, 190, 190 }, { 0x051E, 0x0800, 0x0F00, 0x1700, 0x0000, 0x0000 }},
                    {{ 170, 170, 170, 170, 170, 170 }, { 0x0000, 0x173B, 0x0000, 0x0000, 0x0000, 0x0000 }}},
                    { 0, 2, 2, 2, 2, 2, 1 },
                    { 0, 0, -15, 220, false}};
stStorage sto;
void saveDataFlash() {
  WiFiStorageFile s = WiFiStorage.open("/fs/CT2_Storage");
  if(s) {
    s.erase();
  }
  s.write(&sto, sizeof(stStorage));
  if(DEBUG)
    Serial.println("flash update storage!");
}
void initFlash() {
  bool bInit=false;
  // init storage
  WiFiStorageFile s = WiFiStorage.open("/fs/CT2_Storage");
  if (s) {
    while (s.available()) {
      int ret = s.read(&sto, sizeof(stStorage));
      if(ret<sizeof(stStorage) || !sto.bValue) {
        bInit=true;
        if(DEBUG)
          Serial.println("file storage is not equal!");
      }
      else {
        if(DEBUG)
          Serial.println("file storage read WELL!");
      }
    }
  }
  else {
    if(DEBUG)
      Serial.println("storage IS NOT VALID!");
    bInit=true;
  }
  if(bInit) {
    memcpy(&sto, &preSto, sizeof(stStorage));
    saveDataFlash();
  }
}

void initWifiService() {
  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    if(DEBUG)
      Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    if(DEBUG)
      Serial.println("Please upgrade the firmware");
  }

  initFlash();
  long t=0;
  do {
    checkConnection(millis());
  }
  while(!isOnAir);
  // wait NTP
  if(isOnAir) {
    int cnt=0;
    do {
      delay(1000);
      cnt++;
      t=now();
    }
    while(t<1000 && cnt<9); // attendo che arrivi almeno un pacchetto NTP valido
  }
  if(t<1000) {
    if(DEBUG)
      Serial.println("time from NTP not valid!");
    NVIC_SystemReset(); // system reset
  }
  // NTP ok
}

time_t getNtpTime() {
  WiFiUDP Udp;
  Udp.begin(localPort);
  delay(100);
  while (Udp.parsePacket() > 0) ; // discard any previously received packets
  if(DEBUG)  
    Serial.println("Transmit NTP Request");
  // send NPT packet---------------------------------
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  packetBuffer[0] = 0b11100011;   // LI, Version, Mode
  packetBuffer[1] = 0;     // Stratum, or type of clock
  packetBuffer[2] = 6;     // Polling Interval
  packetBuffer[3] = 0xEC;  // Peer Clock Precision
  // 8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12]  = 49;
  packetBuffer[13]  = 0x4E;
  packetBuffer[14]  = 49;
  packetBuffer[15]  = 52;
  // all NTP fields have been given values, now
  // you can send a packet requesting a timestamp:
  Udp.beginPacket(timeServer, 123); //NTP requests are to port 123
  Udp.write(packetBuffer, NTP_PACKET_SIZE);
  Udp.endPacket();
  //-------------------------------------------------
  //sendNTPpacket(timeServer);
  uint32_t beginWait = millis();
  while (millis() - beginWait < 1500) {
    int size = Udp.parsePacket();
    if (size >= NTP_PACKET_SIZE) {
      if(DEBUG)  
        Serial.println("Receive NTP Response");
      Udp.read(packetBuffer, NTP_PACKET_SIZE);  // read packet into the buffer
      unsigned long secsSince1900;
      // convert four bytes starting at location 40 to a long integer
      secsSince1900 =  (unsigned long)packetBuffer[40] << 24;
      secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
      secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
      secsSince1900 |= (unsigned long)packetBuffer[43];
      return secsSince1900 - 2208988800UL + 1*SECS_PER_HOUR; // +1==Central European Time
    }
  }
  if(DEBUG)  
    Serial.println("No NTP Response :-(");
  return 0; // return 0 if unable to get the time
}
wifiService.cpp PART2C/C++
String text;
char buffer[4096];

void runWifiService(float fTemp) {
  // check connection
  checkConnection(millis());
  if(!isOnAir)
    return;
  // listen for incoming clients
  WiFiClient client = server.available();
  if (client) {
    // an http request ends with a blank line
    while (client.connected()) {
      if(DEBUG)
        Serial.println("\nvvvvvv HTTP vvvvvv");
      if (client.available()) {
        memset(buffer, 0, sizeof(buffer));
        client.read((uint8_t*)buffer, sizeof(buffer));
        text=buffer;
        if(DEBUG)
          Serial.print(text);
        int i1=text.indexOf("Referer:");
        String url="";
        if(i1!=-1) {
          url=text.substring(i1+9);
          url=url.substring(0,url.indexOf("\n")-1);
        }
        if(DEBUG)
          Serial.println("url="+url);
        int ini=text.indexOf("GET /?");
        int fin=text.indexOf(" HTTP");
        if(ini!=-1 && fin!=-1) {  // ricezione dati cambiati
          bool bChangeFH=false;
          buffer[fin]='\0'; // termino stringa fin dove mi serve
          char *ptr=strtok(buffer+ini+6, "&");
          while(ptr!=NULL) {
            String s=ptr;
            ini = s.indexOf("=");
            fin = s.length();
            String var=s.substring(0,ini);
            String val=s.substring(ini+1,fin);
            if(DEBUG) {
              Serial.println("var="+var);
              Serial.println("val="+val);
            }
            if(var[0]=='T') {
              i1=var.substring(1,3).toInt();
              sto.progs[i1/6].T[i1%6]=val.toInt();
            }
            else if(var[0]=='H') {
              i1=var.substring(2,4).toInt();
              sto.progs[i1/6].HM[i1%6]=(int)strtol(val.c_str(), 0, 16);
            }
            else if(var[0]=='W') {
              i1=var.substring(2,3).toInt();
              sto.weekProg[i1]=val.toInt();
            }
            else if(var[0]=='F') {
              if(var[1]=='H') {
                if(sto.forceData.hForce!=val.toInt()) {
                  sto.forceData.hForce=val.toInt();
                  sto.forceData.tFin=now()+sto.forceData.hForce*3600; 
                  bChangeFH=true;
                }
              }
              else if(var[1]=='O') {
                sto.forceData.ofsTemp=val.toInt();
              }
              else if(var[1]=='M') {
                sto.forceData.maxTemp=val.toInt();
              }
              else if(var[1]=='P') {
                sto.forceData.bOFF=val.toInt();
              }
            }
            ptr = strtok(NULL, "&");  // takes a list of delimiters
          }
          if(!bChangeFH)
            saveDataFlash();  // save in storage wifi /fs/ flash
        }
        // create page
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println("Connection: close");  // the connection will be closed after completion of the response
        //client.println("Refresh: 5");  // refresh the page automatically every 5 sec
        client.println();
        memset(buffer, 0, sizeof(buffer));
wifiService.cpp PART4C/C++
bool bDisconnect=false;
long msLastConn=millis();
long msLastStatus=millis();
void checkConnection(long msNow) {
  if(msNow>msLastStatus+1000) {
    status=WiFi.status();
    msLastStatus=msNow;
  }
  // attempt to connect to Wifi network:
  if(status!=WL_CONNECTED) {
    isOnAir=false;
    if(msNow>msLastConn+10000) {
      if(DEBUG) {
        Serial.println(status);
        Serial.print("Attempting to connect to SSID: ");
        Serial.println(ssid);
      }
      // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
      status = WiFi.begin(ssid, pass);
      msLastConn=msNow;
      bDisconnect=true;
    }
  }
  else if(bDisconnect) {
    if(DEBUG)
      Serial.println("Connected to wifi");
    // print wifi status---------------------------------
    if(DEBUG) {
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
    }
    // print your board's IP address:
    IPAddress ip = WiFi.localIP();
    if(DEBUG) {
      Serial.print("IP Address: ");
      Serial.println(ip);
    }
    char text[17];
    sprintf(text, "%d.%d.%d.%d\0", ip[0], ip[1], ip[2], ip[3]);
    ipAddr=text;
    // print the received signal strength:
    long rssi = WiFi.RSSI();
    if(DEBUG) {
      Serial.print("signal strength (RSSI):");
      Serial.print(rssi);
      Serial.println(" dBm");
    }
    //---------------------------------------------------
    if(now()<1000) {
      setSyncProvider(getNtpTime);
      server.begin();
      if(DEBUG)
        Serial.println("Starting connection to server...");
    }
    bDisconnect=false;
    isOnAir=true;
  }
}
wifiService.cpp PART3C/C++
        // create page
        client.println("HTTP/1.1 200 OK");
        client.println("Content-Type: text/html");
        client.println("Connection: close");  // the connection will be closed after completion of the response
        //client.println("Refresh: 5");  // refresh the page automatically every 5 sec
        client.println();
        memset(buffer, 0, sizeof(buffer));
        sprintf(buffer, "\
          <!DOCTYPE HTML>\
          <html><head>\
          <script>if(typeof window.history.pushState == 'function') {window.history.pushState({}, \"Hide\", \"%s\");}</script>\
          </head><body>\
          <h1>CT2_FA settings:</h1>\
          <h3>Current temperature: %.1f&#x2103; %s</h3>\
          <form method=get>\
            Force for hours: <input type=number size=1 name=FH value=%d> <input type=submit value=Force><br>\
          </form>\
          <form method=get>\
            <h3>Programs: T[Deg*10] HM[0xhhmm]</h3>\
            <p style=\"text-align:right;\">AllDay:\
            <input type=text size=1 name=T00 value=%d><input type=text size=4 name=HM00 value=0x%.04x>\
            <input type=text size=1 name=T01 value=%d><input type=text size=4 name=HM01 value=0x%.04x>\
            <input type=text size=1 name=T02 value=%d><input type=text size=4 name=HM02 value=0x%.04x>\
            <input type=text size=1 name=T03 value=%d><input type=text size=4 name=HM03 value=0x%.04x>\
            <input type=text size=1 name=T04 value=%d><input type=text size=4 name=HM04 value=0x%.04x>\
            <input type=text size=1 name=T05 value=%d><input type=text size=4 name=HM05 value=0x%.04x></p>\
            <p style=\"text-align:right;\">Morning+Evening:\
            <input type=text size=1 name=T06 value=%d><input type=text size=4 name=HM06 value=0x%.04x>\
            <input type=text size=1 name=T07 value=%d><input type=text size=4 name=HM07 value=0x%.04x>\
            <input type=text size=1 name=T08 value=%d><input type=text size=4 name=HM08 value=0x%.04x>\
            <input type=text size=1 name=T09 value=%d><input type=text size=4 name=HM09 value=0x%.04x>\
            <input type=text size=1 name=T10 value=%d><input type=text size=4 name=HM10 value=0x%.04x>\
            <input type=text size=1 name=T11 value=%d><input type=text size=4 name=HM11 value=0x%.04x></p>\
            <p style=\"text-align:right;\">Early+Evening:\
            <input type=text size=1 name=T12 value=%d><input type=text size=4 name=HM12 value=0x%.04x>\
            <input type=text size=1 name=T13 value=%d><input type=text size=4 name=HM13 value=0x%.04x>\
            <input type=text size=1 name=T14 value=%d><input type=text size=4 name=HM14 value=0x%.04x>\
            <input type=text size=1 name=T15 value=%d><input type=text size=4 name=HM15 value=0x%.04x>\
            <input type=text size=1 name=T16 value=%d><input type=text size=4 name=HM16 value=0x%.04x>\
            <input type=text size=1 name=T17 value=%d><input type=text size=4 name=HM17 value=0x%.04x></p>\
            <p style=\"text-align:right;\">maiNtenance:\
            <input type=text size=1 name=T18 value=%d><input type=text size=4 name=HM18 value=0x%.04x>\
            <input type=text size=1 name=T19 value=%d><input type=text size=4 name=HM19 value=0x%.04x>\
            <input type=text size=1 name=T20 value=%d><input type=text size=4 name=HM20 value=0x%.04x>\
            <input type=text size=1 name=T21 value=%d><input type=text size=4 name=HM21 value=0x%.04x>\
            <input type=text size=1 name=T22 value=%d><input type=text size=4 name=HM22 value=0x%.04x>\
            <input type=text size=1 name=T23 value=%d><input type=text size=4 name=HM23 value=0x%.04x></p><br>\
            <h3>Day: WP[0=AllDay, 1=M+E, 2=E+E, 3=mNt]</h3>\
            <p>Programs:\
            sun <input type=text size=1 name=WP0 value=%d>\
            mon <input type=text size=1 name=WP1 value=%d>\
            tue <input type=text size=1 name=WP2 value=%d>\
            wed <input type=text size=1 name=WP3 value=%d>\
            thu <input type=text size=1 name=WP4 value=%d>\
            fri <input type=text size=1 name=WP5 value=%d>\
            sat <input type=text size=1 name=WP6 value=%d></p><br>\
            <h3>Settings: T[Deg*10]</h3>\
            <p>General:\
            ofsTemp <input type=text size=1 name=FO value=%d>\
            maxTemp <input type=text size=1 name=FM value=%d>\
            plantOFF <input type=text size=1 name=FP value=%d></p><br>\
            <input type=submit value=Change+Store>\
          </form>\
          </body></html>\n", url.c_str(), fTemp, (bFire?"ON":"OFF"), sto.forceData.hForce,
wifiService.cpp PART2CC/C++
                             sto.progs[0].T[0], sto.progs[0].HM[0],
                             sto.progs[0].T[1], sto.progs[0].HM[1],
                             sto.progs[0].T[2], sto.progs[0].HM[2],
                             sto.progs[0].T[3], sto.progs[0].HM[3],
                             sto.progs[0].T[4], sto.progs[0].HM[4],
                             sto.progs[0].T[5], sto.progs[0].HM[5],
                             sto.progs[1].T[0], sto.progs[1].HM[0],
                             sto.progs[1].T[1], sto.progs[1].HM[1],
                             sto.progs[1].T[2], sto.progs[1].HM[2],
                             sto.progs[1].T[3], sto.progs[1].HM[3],
                             sto.progs[1].T[4], sto.progs[1].HM[4],
                             sto.progs[1].T[5], sto.progs[1].HM[5],
                             sto.progs[2].T[0], sto.progs[2].HM[0],
                             sto.progs[2].T[1], sto.progs[2].HM[1],
                             sto.progs[2].T[2], sto.progs[2].HM[2],
                             sto.progs[2].T[3], sto.progs[2].HM[3],
                             sto.progs[2].T[4], sto.progs[2].HM[4],
                             sto.progs[2].T[5], sto.progs[2].HM[5],
                             sto.progs[3].T[0], sto.progs[3].HM[0],
                             sto.progs[3].T[1], sto.progs[3].HM[1],
                             sto.progs[3].T[2], sto.progs[3].HM[2],
                             sto.progs[3].T[3], sto.progs[3].HM[3],
                             sto.progs[3].T[4], sto.progs[3].HM[4],
                             sto.progs[3].T[5], sto.progs[3].HM[5],
                             sto.weekProg[0], sto.weekProg[1], sto.weekProg[2], sto.weekProg[3], sto.weekProg[4], sto.weekProg[5], sto.weekProg[6],
                             sto.forceData.ofsTemp, sto.forceData.maxTemp, sto.forceData.bOFF);
        if(DEBUG)
          Serial.println(strlen(buffer));
        client.println(buffer);
        if(DEBUG)
          Serial.println("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
        break;
      }
    }
    // give the web browser time to receive the data
    delay(1);
  // close the connection:
    client.stop();
  }
}
arfgsdfgC/C++
No preview (download only).
wifiService.cpp external link
dsgasdfga

Schematics

CT2_FA
Fritzing software
ct2_fa_YDMcOXfyw9.fzz

Comments

Add projectSign up / Login