Ok, I got it working now.
Upload your RA* code through the webwizard to use the latest libraries changes I have made.
Then, upload this to your cloud wifi hub and calibrate.
Code: Select all
#include <FS.h>
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <ESP8266httpUpdate.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <Wire.h>
#include <OneWire.h>
#include <CloudGlobals.h>
// ***********************************************************************
// Change fallback ports below
// Fallback ports will be turned on when cloud connection is lost
// Add each port separated by a |
// For example, if you would like for port 1 and port 5 of Relay Box 1 to be turned on when cloud connection is lost,
// you should add Port1Bit | Port5Bit
// It would look like this:
// #define Relay1FallBack Port1Bit | Port5Bit
#define Relay1FallBack 0
#define Relay2FallBack 0
#define Relay3FallBack 0
#define Relay4FallBack 0
#define Relay5FallBack 0
#define Relay6FallBack 0
#define Relay7FallBack 0
#define Relay8FallBack 0
// Redirect expansion modules to another custom expansion field.
// This is only required if you have multiple modules of the same parameter.
// For example, if you have one Cloud module with an existing salinity module already and wants to add another Cloud module
// with anoter salinity module and report those readings as a Custom Expansion Module 1
// In this case you have to change the CloudCustomModule1 to CUSTOM_SALINITY.
// The values that can be entered are:
// CUSTOM_NONE 0
// CUSTOM_SALINITY 1
// CUSTOM_ORP 2
// CUSTOM_PHEXP 3
// CUSTOM_WL 4
// CUSTOM_MULTI_WL1 5
// CUSTOM_MULTI_WL2 6
// CUSTOM_MULTI_WL3 7
// CUSTOM_MULTI_WL4 8
#define CloudCustomModule1 CUSTOM_NONE
#define CloudCustomModule2 CUSTOM_NONE
#define CloudCustomModule3 CUSTOM_NONE
#define CloudCustomModule4 CUSTOM_NONE
#define CloudCustomModule5 CUSTOM_NONE
#define CloudCustomModule6 CUSTOM_NONE
#define CloudCustomModule7 CUSTOM_NONE
#define CloudCustomModule8 CUSTOM_NONE
// Assign Temperature probes ID
// Only assign temperature probes IDs that you currently are not using in the head unit.
// If you have a total of more than 3 probes, make sure to add the following line on the setup section of the head unit code:
// ReefAngel.AddExtraTempProbes();
// For example, if you only have 1 probe connected to the head unit, assign IDs 2 and 3.
// If you have 2 probes in the head unit and 2 probes in the Cloud Wifi Hub, you must add the above line and you would assign
// IDs 3 and 4.
// Assign ID 0 to unused probes in the Hub.
byte TempProbeIDs[] = {4, 5};
// Do not change anything below
// ***********************************************************************
// solid green - factory reset
// blink green - connecting wifi
// blink blue - configuration required (SoftAP)
// blink magenta - connecting to cloud server
// solid cyan - connected to cloud server
// blinking cyan - transmitting/receiving data
// solid yellow - firmware update
#define LED_GREEN 2
#define LED_BLUE 0
#define LED_RED 16
#define RESET_ALL A0
#define INPUT1 12
#define INPUT2 13
#define TEMP_PIN 14
#define version "1.0.1"
#define MQTTServer "cloud.reefangel.com"
#define MQTTPORT 1883 // MQTT server port
WiFiManager wifiManager;
WiFiClient espClient;
PubSubClient CloudClient(espClient);
Ticker ticker;
OneWire ds(TEMP_PIN);
byte data[2];
byte addr[8];
byte addr1[8];
byte addr2[8];
boolean first_connection = true;
boolean shouldSaveConfig = false;
boolean updating = false;
unsigned long cloudmillis = millis();
unsigned long client_timeout = millis();
unsigned long serial_timeout = millis();
String currentLine = ""; // make a String to hold incoming data from the client
char mqtt_username[32];
char mqtt_password[32];
void APtick()
{
//toggle state
int state = digitalRead(LED_BLUE); // get the current state of GPIO1 pin
digitalWrite(LED_BLUE, !state); // set pin to the opposite state
}
void Wifitick()
{
//toggle state
int state = digitalRead(LED_GREEN); // get the current state of GPIO1 pin
digitalWrite(LED_GREEN, !state); // set pin to the opposite state
}
void Cloudtick()
{
//toggle state
int state = digitalRead(LED_BLUE); // get the current state of GPIO1 pin
digitalWrite(LED_RED, !state); // set pin to the opposite state
digitalWrite(LED_BLUE, !state); // set pin to the opposite state
}
void Datatick()
{
//toggle state
int state = digitalRead(LED_BLUE); // get the current state of GPIO1 pin
digitalWrite(LED_GREEN, !state); // set pin to the opposite state
digitalWrite(LED_BLUE, !state); // set pin to the opposite state
}
void LED_Color(int Red, int Green, int Blue)
{
analogWrite(LED_RED, 1023 - Red);
analogWrite(LED_GREEN, 1023 - Green);
analogWrite(LED_BLUE, 1023 - Blue);
}
int memory_read_int(int address)
{
int temp=0;
temp=EEPROM.read(address)<<8;
temp+=EEPROM.read(address+1);
return temp;
}
void memory_write_int(int address, const int data)
{
if (memory_read_int(address) != data)
{
EEPROM.write(address,data>>8);
EEPROM.write(address+1,data&0xff);
EEPROM.commit();
}
}
unsigned int crc16(int *ptr, byte len)
{
unsigned int crc = 0xFFFF;
byte i;
byte temp = 0;
int test;
while (len--)
{
crc ^= *ptr++;
for (i = 0; i < 8; i++)
{
if (crc & 0x01)
{
crc >>= 1;
crc ^= 0xA001;
}
else
{
crc >>= 1;
}
}
}
return crc;
}
void blink_data_led(byte timer)
{
digitalWrite(LED_RED, LOW);
delay(timer);
digitalWrite(LED_RED, HIGH);
}
void Publish(char* pub_buffer, char* buffer)
{
CloudClient.publish(pub_buffer, buffer);
Serial.print(pub_buffer);
Serial.print(": ");
Serial.println(buffer);
blink_data_led(50);
}
void reconnect() {
// Loop until we're reconnected
if (!CloudClient.connected()) {
cloudmillis = millis();
// Serial.print(F("Username: "));
// Serial.println(CLOUD_USERNAME);
Serial.println("Connecting to cloud server...");
// Attempt to connect
//Serial.println(sub_buffer);
if (CloudClient.connect(clientid, mqtt_username, mqtt_password)) {
Serial.println("Connected");
// Once connected, publish an announcement...
Serial.print("Subscribing to ");
Serial.println(sub_buffer);
CloudClient.subscribe(sub_buffer);
Publish(pub_buffer, "all:0");
ticker.detach();
LED_Color(0, 1023, 1023);
//Serial.swap();
} else {
Serial.print("Failed, rc=");
Serial.print(CloudClient.state());
Serial.println(" try again in 30 seconds");
}
}
}
void ApplyCalibration(byte module, byte type)
{
CustomExpansion[module - 1] = type;
switch (type)
{
case CUSTOM_SALINITY:
sprintf(pub_salinity, "cexp:%d:", module - 1);
break;
case CUSTOM_ORP:
sprintf(pub_orp, "cexp:%d:", module - 1);
break;
case CUSTOM_PHEXP:
sprintf(pub_phexp, "cexp:%d:", module - 1);
break;
case CUSTOM_WL:
sprintf(pub_wl, "cexp:%d:", module - 1);
sprintf(pub_custom_wl, "cexpc:%d:", module - 1);
break;
case CUSTOM_MULTI_WL1:
case CUSTOM_MULTI_WL2:
case CUSTOM_MULTI_WL3:
case CUSTOM_MULTI_WL4:
sprintf(pub_multiwl, "cexp:%d:", module - 1);
sprintf(pub_custom_multiwl, "cexpc:%d:", module - 1);
break;
case CUSTOM_NONE:
break;
}
}
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void configModeCallback (WiFiManager *myWiFiManager) {
LED_Color(0, 0, 0);
ticker.detach();
Serial.println("Entered config mode");
WiFi.softAPIP();
ticker.attach(0.5, APtick);
}
void WifiCheckCallback () {
WiFi.softAPdisconnect(true);
LED_Color(0, 0, 0);
ticker.detach();
Serial.println("Checking Wifi Credentials");
ticker.attach(0.5, Wifitick);
}
void callback(char* topic, byte* payload, unsigned int length) {
boolean data_found = false;
int payload_data = 0;
byte data_index = 0;
Serial.print("cloud:");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
if (payload[0] == 'R' && payload[1] == 'O' && payload[2] == 'F' && payload[3] == 'F' && payload[5] == ':')
{
data_found = true;
data_index = payload[4] - '0' - 1;
for (byte a = 6; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
RelayMaskOffE[data_index] = payload_data;
}
else if (payload[0] == 'R' && payload[1] == 'O' && payload[2] == 'N' && payload[4] == ':')
{
data_found = true;
data_index = payload[3] - '0' - 1;
for (byte a = 5; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
RelayMaskOnE[data_index] = payload_data;
}
else if (payload[0] == 'R' && payload[2] == ':')
{
data_found = true;
data_index = payload[1] - '0' - 1;
for (byte a = 3; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
RelayDataE[data_index] = payload_data;
}
else if (payload[0] == 'P' && payload[1] == 'W' && payload[2] == 'M' && payload[3] == 'E' && payload[5] == ':')
{
data_found = true;
data_index = payload[4] - '0';
for (byte a = 6; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
ExpansionChannel[data_index] = payload_data;
}
else if (payload[0] == 'P' && payload[1] == 'W' && payload[2] == 'M' && payload[3] == 'E' && payload[5] == 'O' && payload[6] == ':')
{
data_found = true;
data_index = payload[4] - '0';
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
ExpansionChannelOverride[data_index] = payload_data;
}
else if (payload[0] == 'P' && payload[1] == 'W' && payload[2] == 'M' && payload[3] == '1' && payload[4] == '6' && payload[5] == 'E' && payload[8] == ':')
{
data_found = true;
data_index = (payload[6] - '0') * 10;
data_index += (payload[7] - '0');
for (byte a = 9; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
Expansion16Channel[data_index] = payload_data;
}
else if (payload[0] == 'P' && payload[1] == 'W' && payload[2] == 'M' && payload[3] == '1' && payload[4] == '6' && payload[5] == 'E' && payload[6] == 'O' && payload[9] == ':')
{
data_found = true;
data_index = (payload[7] - '0') * 10;
data_index += (payload[8] - '0');
for (byte a = 10; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
Expansion16ChannelOverride[data_index] = payload_data;
}
else if (payload[0] == 'O' && payload[1] == 'R' && payload[2] == 'P' && payload[3] == 'C' && payload[4] == ':' && ORPFound)
{
Serial.println(F("ORP calibration"));
data_found = true;
if (payload[5] == '0')
ORPCal = false;
else if (payload[5] == '1')
ORPCal = true;
else if (payload[5] == '2')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
CalVal1 = payload_data;
}
else if (payload[5] == '3')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
memory_write_int(Mem_I_ORPMin, CalVal1);
memory_write_int(Mem_I_ORPMax, payload_data);
ORPMin = CalVal1;
ORPMax = payload_data;
ORPCal = false;
}
}
else if (payload[0] == 'S' && payload[1] == 'A' && payload[2] == 'L' && payload[3] == 'C' && payload[4] == ':' && SalinityFound)
{
Serial.println(F("Sal calibration"));
data_found = true;
if (payload[5] == '0')
SalCal = false;
else if (payload[5] == '1')
SalCal = true;
else if (payload[5] == '2')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
memory_write_int(Mem_I_SalMax, payload_data);
SalMax = payload_data;
SalCal = false;
}
}
else if (payload[0] == 'P' && payload[1] == 'H' && payload[2] == 'E' && payload[3] == 'C' && payload[4] == ':' && PHExpFound)
{
Serial.println(F("PH Exp calibration"));
data_found = true;
if (payload[5] == '0')
PHExpCal = false;
else if (payload[5] == '1')
PHExpCal = true;
else if (payload[5] == '2')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
CalVal1 = payload_data;
}
else if (payload[5] == '3')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
memory_write_int(Mem_I_PHExpMin, CalVal1);
memory_write_int(Mem_I_PHExpMax, payload_data);
PHExpMin = CalVal1;
PHExpMax = payload_data;
PHExpCal = false;
}
}
else if (payload[0] == 'W' && payload[1] == 'L' && payload[3] == 'C' && payload[4] == ':' && (WLFound || MultiWLFound))
{
Serial.println(F("WL calibration"));
data_found = true;
data_index = payload[2] - '0';
if (payload[5] == '0')
WLCal[data_index] = false;
else if (payload[5] == '1')
{
if (data_index == 0 && WLFound)
WLCal[data_index] = true;
if (data_index > 0 && MultiWLFound)
WLCal[data_index] = true;
}
else if (payload[5] == '2')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
CalVal1 = payload_data;
}
else if (payload[5] == '3')
{
for (byte a = 7; a < length; a++)
{
if (payload[a] != 10 && payload[a] != 13)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
}
if (data_index == 0)
{
memory_write_int(Mem_I_WaterLevelMin, CalVal1);
memory_write_int(Mem_I_WaterLevelMax, payload_data);
}
if (data_index > 0 && data_index < 5)
{
memory_write_int(Mem_I_WaterLevel1Min + (data_index * 2) - 2, CalVal1);
memory_write_int(Mem_I_WaterLevel1Max + (data_index * 2) - 2, payload_data);
}
WLMin[data_index] = CalVal1;
WLMax[data_index] = payload_data;
WLCal[data_index] = false;
}
}
else if (payload[0] == 'C' && payload[1] == 'E' && payload[2] == 'X' && payload[3] == 'P' && payload[5] == 'C' && payload[6] == ':')
{
Serial.println(F("Custom Exp calibration"));
data_found = true;
data_index = payload[4] - '0';
if (payload[7] == '0')
{
if (pub_salinity[0] == 'c' && CustomExpansion[data_index] == CUSTOM_SALINITY) SalCal = false;
if (pub_orp[0] == 'c' && CustomExpansion[data_index] == CUSTOM_ORP) ORPCal = false;
if (pub_phexp[0] == 'c' && CustomExpansion[data_index] == CUSTOM_PHEXP) PHExpCal = false;
if (pub_wl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_WL) WLCal[0] = false;
for (int a = 1; a < WL_CHANNELS; a++)
if (pub_multiwl[0] == 'c' && CustomExpansion[data_index] >= CUSTOM_MULTI_WL1 && CustomExpansion[data_index] <= CUSTOM_MULTI_WL4) WLCal[a] = false;
}
else if (payload[7] == '1')
{
if (pub_salinity[0] == 'c' && CustomExpansion[data_index] == CUSTOM_SALINITY) SalCal = true;
if (pub_orp[0] == 'c' && CustomExpansion[data_index] == CUSTOM_ORP) ORPCal = true;
if (pub_phexp[0] == 'c' && CustomExpansion[data_index] == CUSTOM_PHEXP) PHExpCal = true;
if (pub_wl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_WL) WLCal[0] = true;
if (pub_multiwl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_MULTI_WL1) WLCal[1] = true;
if (pub_multiwl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_MULTI_WL2) WLCal[2] = true;
if (pub_multiwl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_MULTI_WL3) WLCal[3] = true;
if (pub_multiwl[0] == 'c' && CustomExpansion[data_index] == CUSTOM_MULTI_WL4) WLCal[4] = true;
}
else if (payload[7] == '2')
{
for (byte a = 9; a < length; a++)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
CalVal1 = payload_data;
}
else if (payload[7] == '3')
{
for (byte a = 9; a < length; a++)
{
payload_data *= 10;
payload_data += payload[a] - '0';
}
if (pub_salinity[0] == 'c')
{
memory_write_int(Mem_I_SalMax, payload_data);
SalMax = payload_data;
SalCal = false;
}
if (pub_orp[0] == 'c')
{
memory_write_int(Mem_I_ORPMin, CalVal1);
memory_write_int(Mem_I_ORPMax, payload_data);
ORPMin = CalVal1;
ORPMax = payload_data;
ORPCal = false;
}
if (pub_phexp[0] == 'c')
{
memory_write_int(Mem_I_PHExpMin, CalVal1);
memory_write_int(Mem_I_PHExpMax, payload_data);
PHExpMin = CalVal1;
PHExpMax = payload_data;
PHExpCal = false;
}
if (pub_wl[0] == 'c')
{
memory_write_int(Mem_I_WaterLevelMin, CalVal1);
memory_write_int(Mem_I_WaterLevelMax, payload_data);
WLMin[0] = CalVal1;
WLMax[0] = payload_data;
WLCal[0] = false;
}
for (int a = 1; a < WL_CHANNELS; a++)
if (pub_multiwl[0] == 'c' && WLCal[a] == true)
{
memory_write_int(Mem_I_WaterLevel1Min + (a * 2) - 2, CalVal1);
memory_write_int(Mem_I_WaterLevel1Max + (a * 2) - 2, payload_data);
WLMin[a] = CalVal1;
WLMax[a] = payload_data;
WLCal[a] = false;
}
}
}
if (data_found)
{
blink_data_led(30);
for (int a = 0; a < length; a++)
Serial.write(payload[a]);
Serial.println();
}
}
void setup() {
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
pinMode(LED_RED, OUTPUT);
pinMode(INPUT1, INPUT_PULLUP);
pinMode(INPUT2, INPUT_PULLUP);
digitalWrite(LED_GREEN, LOW);
digitalWrite(LED_BLUE, HIGH);
digitalWrite(LED_RED, HIGH);
randomSeed(analogRead(0));
wifi_station_set_hostname( "ReefAngelCloudHub" );
Serial.begin(57600);
Serial.setRxBufferSize(2048);
EEPROM.begin(512);
Wire.begin();
wifiManager.setDebugOutput(true);
Serial.println("");
Serial.print("Current version: ");
Serial.println(version);
SalinityFound = false;
ORPFound = false;
PHExpFound = false;
WLFound = false;
MultiWLFound = false;
HumidityFound = false;
sprintf(pub_salinity, "sal");
sprintf(pub_orp, "orp");
sprintf(pub_phexp, "phe");
sprintf(pub_wl, "wl");
sprintf(pub_multiwl, "wl");
sprintf(pub_humidity, "hum");
// Temperature
byte count = 0;
while (ds.search(addr))
{
if (addr[0] == 0x28)
{
count++;
if (count == 1) memcpy(addr1, addr, 8);
if (count == 2) memcpy(addr2, addr, 8);
}
}
ds.reset_search();
Serial.print(count);
Serial.println(" temperature probe(s) found");
// Relay
for ( byte EID = 0; EID < MAX_RELAY_EXPANSION_MODULES; EID++ )
{
RelayDataE[EID] = 0;
RelayMaskOnE[EID] = 0;
RelayMaskOffE[EID] = 0xff;
}
RelayFallBackE[0] = Relay1FallBack;
RelayFallBackE[1] = Relay2FallBack;
RelayFallBackE[2] = Relay3FallBack;
RelayFallBackE[3] = Relay4FallBack;
RelayFallBackE[4] = Relay5FallBack;
RelayFallBackE[5] = Relay6FallBack;
RelayFallBackE[6] = Relay7FallBack;
RelayFallBackE[7] = Relay8FallBack;
// Dimming
lastcrc = -1;
for ( byte a = 0; a < PWM_EXPANSION_CHANNELS; a++ )
{
ExpansionChannel[a] = 0;
ExpansionChannelOverride[a] = 255;
}
// 16 Channel Dimming
lastcrc16 = -1;
for ( byte a = 0; a < PWM16_EXPANSION_CHANNELS; a++ )
{
Expansion16Channel[a] = 0;
Expansion16ChannelOverride[a] = 255;
}
// IO
Params.IO = 63;
OldParams.IO = 63;
// Leak
Params.Leak = 0;
OldParams.Leak = 0;
// ORP
Params.ORP = 0;
OldParams.ORP = 0;
ORPCal = false;
ORPMin = memory_read_int(Mem_I_ORPMin);
if (ORPMin == 65535) ORPMin = 0;
ORPMax = memory_read_int(Mem_I_ORPMax);
// Salinity
Params.Salinity = 0;
OldParams.Salinity = 0;
SalCal = false;
SalMax = memory_read_int(Mem_I_SalMax);
// pH Exp
Params.PHExp = 0;
OldParams.PHExp = 0;
PHExpCal = false;
PHExpMin = memory_read_int(Mem_I_PHExpMin);
if (PHExpMin == 65535) PHExpMin = 0;
PHExpMax = memory_read_int(Mem_I_PHExpMax);
// Humidity
Params.Humidity = 0;
OldParams.Humidity = 0;
// Water Level
for (int a = 0; a < WL_CHANNELS; a++)
{
Params.WL[a] = 0;
OldParams.WL[a] = 0;
WLCal[a] = false;
}
WLMin[0] = memory_read_int(Mem_I_WaterLevelMin);
WLMax[0] = memory_read_int(Mem_I_WaterLevelMax);
WLMin[1] = memory_read_int(Mem_I_WaterLevel1Min);
WLMax[1] = memory_read_int(Mem_I_WaterLevel1Max);
WLMin[2] = memory_read_int(Mem_I_WaterLevel2Min);
WLMax[2] = memory_read_int(Mem_I_WaterLevel2Max);
WLMin[3] = memory_read_int(Mem_I_WaterLevel3Min);
WLMax[3] = memory_read_int(Mem_I_WaterLevel3Max);
WLMin[4] = memory_read_int(Mem_I_WaterLevel4Min);
WLMax[4] = memory_read_int(Mem_I_WaterLevel4Max);
for (int a = 0; a < 5; a++)
{
if (WLMin[a] == 65535) WLMin[a] = 0;
}
ApplyCalibration(1, CloudCustomModule1);
ApplyCalibration(2, CloudCustomModule2);
ApplyCalibration(3, CloudCustomModule3);
ApplyCalibration(4, CloudCustomModule4);
ApplyCalibration(5, CloudCustomModule5);
ApplyCalibration(6, CloudCustomModule6);
ApplyCalibration(7, CloudCustomModule7);
ApplyCalibration(8, CloudCustomModule8);
if (analogRead(RESET_ALL) < 50)
{
// updating=true;
Serial.println("Resetting");
EEPROM.write(128, 0);
EEPROM.commit();
ESP.reset();
while (1);
}
wifiManager.setVersion(version);
if (EEPROM.read(128) != 1)
{
wifiManager.resetSettings();
SPIFFS.format();
EEPROM.write(128, 1);
EEPROM.commit();
}
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
Serial.println("\nparsed json");
strcpy(mqtt_username, json["mqtt_username"]);
strcpy(mqtt_password, json["mqtt_password"]);
} else {
Serial.println("failed to load json config");
}
}
}
} else {
Serial.println("failed to mount FS");
}
WiFiManagerParameter custom_mqtt_username("Cloud Username", "Cloud Username", mqtt_username, 40);
WiFiManagerParameter custom_mqtt_password("Cloud Password", "Cloud Password", mqtt_password, 40);
wifiManager.addParameter(&custom_mqtt_username);
wifiManager.addParameter(&custom_mqtt_password);
wifiManager.setSaveConfigCallback(saveConfigCallback);
wifiManager.setAPCallback(configModeCallback);
wifiManager.setCheckWifiCallback(WifiCheckCallback);
LED_Color(0, 0, 0);
ticker.attach(0.5, Wifitick);
wifiManager.autoConnect("ReefAngelCloudHub");
ticker.detach();
LED_Color(900, 0, 1023);
CloudClient.setServer(MQTTServer, MQTTPORT);
CloudClient.setCallback(callback);
strcpy(mqtt_username, custom_mqtt_username.getValue());
strcpy(mqtt_password, custom_mqtt_password.getValue());
Serial.print("username: ");
Serial.println(mqtt_username);
// Serial.print("password: ");
// Serial.println(mqtt_password);
sprintf(clientid, "%s%02d", mqtt_username, random(10000));
sprintf(pub_buffer, "%s/in", mqtt_username);
sprintf(sub_buffer, "%s/out/#", mqtt_username);
Serial.println("Start");
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["mqtt_username"] = mqtt_username;
json["mqtt_password"] = mqtt_password;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.printTo(Serial);
Serial.println("");
json.printTo(configFile);
configFile.close();
//end save
}
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
void loop() {
if ((analogRead(RESET_ALL) < 50) && !updating)
{
if (WiFi.status() == WL_CONNECTED)
{
updating = true;
ticker.detach();
LED_Color(1023, 900, 0);
Serial.println("Updating...");
ESPhttpUpdate.update("forum.reefangel.com", 80, "/firmware/CloudWifiESP8266Hub.ino.bin");
}
else
{
Serial.println("Resetting");
EEPROM.write(128, 0);
EEPROM.commit();
ESP.reset();
while (1);
}
}
if (!CloudClient.connected() && (((millis() - cloudmillis) > 30000) || first_connection)) {
first_connection = false;
LED_Color(0, 0, 0);
ticker.detach();
ticker.attach(0.5, Cloudtick);
reconnect();
}
CloudClient.loop();
// Relay
for ( byte EID = 0; EID < MAX_RELAY_EXPANSION_MODULES; EID++ )
{
byte TempRelay = RelayDataE[EID];
TempRelay &= RelayMaskOffE[EID];
TempRelay |= RelayMaskOnE[EID];
if (!CloudClient.connected())
TempRelay = RelayFallBackE[EID];
Wire.beginTransmission(I2CExpModule + EID);
Wire.write(~TempRelay); // MSB
Wire.endTransmission();
}
// Dimming
byte thiscrc = 0;
for ( byte a = 0; a < PWM_EXPANSION_CHANNELS; a++ )
{
thiscrc += ExpansionChannel[a] * (a + 1);
thiscrc += ExpansionChannelOverride[a] * (a + 1);
}
if (millis() % 60000 < 200) lastcrc = -1;
if (lastcrc != thiscrc || millis() < 5000)
{
lastcrc = thiscrc;
// setup PCA9685 for data receive
// we need this to make sure it will work if connected ofter controller is booted, so we need to send it all the time.
Wire.beginTransmission(I2CPWM_PCA9685);
Wire.write((uint8_t)0);
Wire.write(0xa1);
Wire.endTransmission();
for ( byte a = 0; a < PWM_EXPANSION_CHANNELS; a++ )
{
int data;
if (ExpansionChannelOverride[a] <= 100)
data = ExpansionChannelOverride[a] * 40.96;
else
data = ExpansionChannel[a] * 40.96;
Wire.beginTransmission(I2CPWM_PCA9685);
Wire.write(0x8 + (4 * a));
Wire.write(data & 0xff);
Wire.write(data >> 8);
Wire.endTransmission();
}
}
// 16 Channel Dimming
int thiscrc16 = 0;
for ( byte a = 0; a < PWM16_EXPANSION_CHANNELS; a++ )
{
thiscrc16 += Expansion16Channel[a] * (a + 1);
thiscrc16 += Expansion16ChannelOverride[a] * (a + 1);
}
if (millis() % 60000 < 200) lastcrc16 = -1;
if (lastcrc16 != thiscrc16 || millis() < 5000)
{
lastcrc16 = thiscrc16;
// setup PCA9685 for data receive
// we need this to make sure it will work if connected ofter controller is booted, so we need to send it all the time.
Wire.beginTransmission(I2CPWM_16CH_PCA9685);
Wire.write((uint8_t)0);
Wire.write(0xa1);
Wire.endTransmission();
for ( byte a = 0; a < PWM16_EXPANSION_CHANNELS; a++ )
{
int data;
if (Expansion16ChannelOverride[a] <= 100)
data = Expansion16ChannelOverride[a];
else
data = Expansion16Channel[a];
Wire.beginTransmission(I2CPWM_16CH_PCA9685);
Wire.write(0x8 + (4 * a));
Wire.write(data & 0xff);
Wire.write(data >> 8);
Wire.endTransmission();
}
}
if (CloudClient.connected())
{
// IO
Params.IO = 63;
Wire.requestFrom(I2CIO_PCF8574, 1);
if (Wire.available())
Params.IO = Wire.read();
if (digitalRead(INPUT1) == HIGH) Params.IO += 64;
if (digitalRead(INPUT2) == HIGH) Params.IO += 128;
if (Params.IO != OldParams.IO)
{
OldParams.IO = Params.IO;
sprintf(buffer, "io:%d", Params.IO);
Publish(pub_buffer, buffer);
}
// Leak
int iLeak = 0;
Wire.requestFrom(I2CLeak, 2);
if (Wire.available())
{
iLeak = Wire.read();
iLeak = iLeak << 8;
iLeak += Wire.read();
Params.Leak = iLeak > 2000;
}
if (Params.Leak != OldParams.Leak)
{
OldParams.Leak = Params.Leak;
sprintf(buffer, "leak:%d", Params.Leak);
Publish(pub_buffer, buffer);
}
if (millis() - Paramsmillis > 1000)
{
Paramsmillis = millis();
// Temperature
if (addr1[0] != 0)
{
ds.reset();
ds.select(addr1);
ds.write(0xBE); // Read Scratchpad
for (byte i = 0; i < 2; i++)
{
data[i] = ds.read();
}
Params.Temp[1] = (data[1] << 8) + data[0]; //take the two bytes from the response relating to temperature
Params.Temp[1] = Params.Temp[1] / 1.6;
if (Params.Temp[1] == 0) Params.Temp[1] = 0;
if (Params.Temp[1] > 850) Params.Temp[1] = 0;
Params.Temp[1] = Params.Temp[1] * 1.8 + 320;
if (Params.Temp[1] != OldParams.Temp[1])
{
OldParams.Temp[1] = Params.Temp[1];
sprintf(buffer, "t:%d:%d", TempProbeIDs[0], Params.Temp[1]);
if (TempProbeIDs[0] != 0) Publish(pub_buffer, buffer);
}
}
if (addr2[0] != 0)
{
ds.reset();
ds.select(addr2);
ds.write(0xBE); // Read Scratchpad
for (byte i = 0; i < 2; i++)
{
data[i] = ds.read();
}
Params.Temp[2] = (data[1] << 8) + data[0]; //take the two bytes from the response relating to temperature
Params.Temp[2] = Params.Temp[2] / 1.6;
if (Params.Temp[2] == 0) Params.Temp[2] = 0;
if (Params.Temp[2] > 850) Params.Temp[2] = 0;
Params.Temp[2] = Params.Temp[2] * 1.8 + 320;
if (Params.Temp[2] != OldParams.Temp[2])
{
OldParams.Temp[2] = Params.Temp[2];
sprintf(buffer, "t:%d:%d", TempProbeIDs[1], Params.Temp[2]);
if (TempProbeIDs[1] != 0) Publish(pub_buffer, buffer);
}
}
// ORP
unsigned long temporp = 0;
int iORP = 0;
for (int a = 0; a < 20; a++)
{
Wire.requestFrom(I2CORP, 2);
if (Wire.available())
{
iORP = Wire.read();
iORP = iORP << 8;
iORP += Wire.read();
}
temporp += iORP;
}
temporp = temporp / 20;
if (temporp != 0)
{
Params.ORP = map(temporp, ORPMin, ORPMax, 0, 470); // apply the calibration to the sensor reading
Params.ORP = constrain(Params.ORP, 0, 550);
if (pub_orp[0] == 'o') ORPFound = true;
}
if (ORPCal)
{
if (pub_orp[0] == 'o') sprintf(buffer, "%sc:%d", pub_orp, temporp);
if (pub_orp[0] == 'c')
{
sprintf(buffer, "cexpc:%c:%d", pub_orp[5], temporp);
}
Publish(pub_buffer, buffer);
}
else
{
if (Params.ORP != OldParams.ORP)
{
OldParams.ORP = Params.ORP;
sprintf(buffer, "%s:%d", pub_orp, Params.ORP);
Publish(pub_buffer, buffer);
}
}
// Salinity
unsigned long tempsal = 0;
int iSAL = 0;
for (int a = 0; a < 20; a++)
{
Wire.requestFrom(I2CSalinity, 2);
if (Wire.available())
{
iSAL = Wire.read();
iSAL = iSAL << 8;
iSAL += Wire.read();
}
tempsal += iSAL;
}
tempsal = tempsal / 20;
if (tempsal != 0)
{
Params.Salinity = map(tempsal, 0, SalMax, 60, 350); // apply the calibration to the sensor reading
if (pub_salinity[0] == 's') SalinityFound = true;
}
if (SalCal)
{
if (pub_salinity[0] == 's') sprintf(buffer, "%sc:%d", pub_salinity, tempsal);
if (pub_salinity[0] == 'c')
{
sprintf(buffer, "cexpc:%c:%d", pub_salinity[5], tempsal);
}
Publish(pub_buffer, buffer);
}
else
{
if (Params.Salinity != OldParams.Salinity)
{
OldParams.Salinity = Params.Salinity;
sprintf(buffer, "%s:%d", pub_salinity, Params.Salinity);
Publish(pub_buffer, buffer);
}
}
// pH Exp
unsigned long tempphexp = 0;
int iPHExp = 0;
for (int a = 0; a < 20; a++)
{
Wire.requestFrom(I2CPH, 2);
if (Wire.available())
{
iPHExp = Wire.read();
iPHExp = iPHExp << 8;
iPHExp += Wire.read();
}
tempphexp += iPHExp;
}
tempphexp = tempphexp / 20;
if (tempphexp != 0)
{
Params.PHExp = map(tempphexp, PHExpMin, PHExpMax, 700, 1000); // apply the calibration to the sensor reading
Params.PHExp = constrain(Params.PHExp, 100, 1400);
if (pub_phexp[0] == 'p') PHExpFound = true;
}
if (PHExpCal)
{
if (pub_orp[0] == 'p') sprintf(buffer, "%sc:%d", pub_phexp, tempphexp);
if (pub_orp[0] == 'c')
{
sprintf(buffer, "cexpc:%c:%d", pub_phexp[5], tempphexp);
}
Publish(pub_buffer, buffer);
}
else
{
if (Params.PHExp != OldParams.PHExp)
{
OldParams.PHExp = Params.PHExp;
sprintf(buffer, "%s:%d", pub_phexp, Params.PHExp);
Publish(pub_buffer, buffer);
}
}
// PAR
unsigned long temppar = 0;
int iPAR = 0;
for (int a = 0; a < 20; a++)
{
Wire.requestFrom(I2CPAR, 2);
if (Wire.available())
{
iPAR = Wire.read();
iPAR = iPAR << 8;
iPAR += Wire.read();
}
temppar += iPAR;
}
temppar = temppar / 20;
if (temppar != 0)
{
temppar *= 5000; // apply the calibration to the sensor reading
temppar /= 8192;
Params.PAR = temppar;
}
if (Params.PAR != OldParams.PAR)
{
OldParams.PAR = Params.PAR;
sprintf(buffer, "par:%d", Params.PAR);
Publish(pub_buffer, buffer);
}
// Humidity
int iHumidity = 0;
int reply[10];
Wire.beginTransmission(I2CHumidity);
Wire.endTransmission(); // For some reason, it needs this to work??? Bug with sensor??
Wire.beginTransmission(I2CHumidity);
Wire.write(0x3); // 0x3 for read 0x10 for write to registers
Wire.write((byte)0x0); // start at address 0x0 for humidity
Wire.write(2); // request 2 bytes data for humidity or 4 bytes for temperature+humidity
Wire.endTransmission();
Wire.requestFrom(I2CHumidity, 6); // Request 6 bytes
for (int i = 0; i < 6; i++)
if (Wire.available()) reply[i] = Wire.read();
if (reply[0] == 0x3 && reply[1] == 0x2) // The response need to contain function (0x3) and length of data (0x2)
{
int crc = reply[5];
crc <<= 8;
crc += reply[4];
if (crc == crc16(reply, 4))
{
iHumidity = reply[2];
iHumidity <<= 8;
iHumidity += reply[3];
}
}
Params.Humidity = iHumidity;
if (Params.Humidity != OldParams.Humidity)
{
OldParams.Humidity = Params.Humidity;
sprintf(buffer, "hum:%d", Params.Humidity);
Publish(pub_buffer, buffer);
}
// Water Level
for (int i = 0; i < WL_CHANNELS; i++)
{
unsigned long tempwl = 0;
int iWL = 0;
for (int a = 0; a < 20; a++)
{
if (i == 0)
{
Wire.requestFrom(I2CWaterLevel, 2);
if (Wire.available())
{
iWL = Wire.read();
iWL = iWL << 8;
iWL += Wire.read();
}
tempwl += iWL;
if (tempwl != 0 && pub_wl[0] == 'w') WLFound = true;
}
else
{
Wire.beginTransmission(I2CMultiWaterLevel);
Wire.write(1); // Config Pointer
byte addr = (0xb + i) << 4; // Select which channel to read
addr += 0x03; // Programmable Gain
Wire.write(addr);
Wire.write(0x83);
Wire.endTransmission();
delay(10); // It takes 10ms for conversion to be completed
Wire.beginTransmission(I2CMultiWaterLevel);
Wire.write((uint8_t)0); // Convert Pointer
Wire.endTransmission();
Wire.requestFrom(I2CMultiWaterLevel, 2); // Request converted value
if (Wire.available())
{
iWL = Wire.read();
iWL = iWL << 8;
iWL += Wire.read();
}
tempwl += iWL >> 4;
if (tempwl != 0 && pub_multiwl[0] == 'w') MultiWLFound = true;
}
}
tempwl = tempwl / 20;
if (tempwl != 0)
{
Params.WL[i] = map(tempwl, WLMin[i], WLMax[i], 0, 100); // apply the calibration to the sensor reading
Params.WL[i] = constrain(Params.WL[i], 0, 255);
}
if (WLCal[i])
{
if (i == 0)
{
if (pub_wl[0] == 'c')
sprintf(buffer, "%s%d", pub_custom_wl, tempwl);
else
sprintf(buffer, "%sc:%d", pub_wl, tempwl);
}
else
{
if (pub_multiwl[0] == 'c')
sprintf(buffer, "%s%d", pub_custom_multiwl, tempwl);
else
sprintf(buffer, "%sc:%d", pub_multiwl, tempwl);
}
Publish(pub_buffer, buffer);
}
else
{
if (Params.WL[i] != OldParams.WL[i])
{
OldParams.WL[i] = Params.WL[i];
if (i == 0)
{
if (pub_wl[0] == 'c')
sprintf(buffer, "%s%d", pub_wl, Params.WL[i]);
else
sprintf(buffer, "%s:%d:%d", pub_wl, i, Params.WL[i]);
}
else
{
if (pub_multiwl[0] == 'c')
sprintf(buffer, "%s%d", pub_multiwl, Params.WL[i]);
else
sprintf(buffer, "%s:%d:%d", pub_multiwl, i, Params.WL[i]);
}
Publish(pub_buffer, buffer);
}
}
}
ds.reset();
ds.select(addr1);
ds.write(0x44, 0);
ds.reset();
ds.select(addr2);
ds.write(0x44, 0);
}
}
}