A => firmware/remote_sensors_mkr1000/include/Credentials.h +89 -0
@@ 0,0 1,89 @@
+/****************************************************************************************************************************
+ Credentials.h
+ For SAMD21 MKR1000 boards using WiFi101 Modules/Shields
+
+ WiFiManager_Generic_WM_Lite is a library for the Mega, Teensy, SAM DUE, SAMD and STM32 boards
+ (https://github.com/khoih-prog/WiFiManager_Generic_Lite) to enable store Credentials in EEPROM/LittleFS for easy
+ configuration/reconfiguration and autoconnect/autoreconnect of WiFi and other services without Hardcoding.
+
+ Built by Khoi Hoang https://github.com/khoih-prog/WiFiManager_Generic_Lite
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+
+#ifndef Credentials_h
+#define Credentials_h
+
+#include "defines.h"
+
+/// Start Default Config Data //////////////////
+
+/*
+#define SSID_MAX_LEN 32
+//From v1.0.3, WPA2 passwords can be up to 63 characters long.
+#define PASS_MAX_LEN 64
+
+typedef struct
+{
+ char wifi_ssid[SSID_MAX_LEN];
+ char wifi_pw [PASS_MAX_LEN];
+} WiFi_Credentials;
+
+#define NUM_WIFI_CREDENTIALS 2
+
+// Configurable items besides fixed Header, just add board_name
+#define NUM_CONFIGURABLE_ITEMS ( ( 2 * NUM_WIFI_CREDENTIALS ) + 1 )
+////////////////
+
+typedef struct Configuration
+{
+ char header [16];
+ WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS];
+ char board_name [24];
+ int checkSum;
+} WIFI_GENERIC_Configuration;
+*/
+
+#define TO_LOAD_DEFAULT_CONFIG_DATA false
+
+#if TO_LOAD_DEFAULT_CONFIG_DATA
+
+// This feature is primarily used in development to force a known set of values as Config Data
+// It will NOT force the Config Portal to activate. Use DRD or erase Config Data with Blynk.clearConfigData()
+
+// Used mostly for development and debugging. FORCES default values to be loaded each run.
+// Config Portal data input will be ignored and overridden by DEFAULT_CONFIG_DATA
+//bool LOAD_DEFAULT_CONFIG_DATA = true;
+
+// Used mostly once debugged. Assumes good data already saved in device.
+// Config Portal data input will be override DEFAULT_CONFIG_DATA
+bool LOAD_DEFAULT_CONFIG_DATA = false;
+
+
+WIFI_GENERIC_Configuration defaultConfig =
+{
+ //char header[16], dummy, not used
+ "WIFI_GENERIC",
+ // WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS];
+ // WiFi_Credentials.wifi_ssid and WiFi_Credentials.wifi_pw
+ "SSID1", "password1",
+ "SSID2", "password2",
+ //char board_name [24];
+ "SAMD-Control",
+ // terminate the list
+ //int checkSum, dummy, not used
+ 0
+ /////////// End Default Config Data /////////////
+};
+
+#else
+
+bool LOAD_DEFAULT_CONFIG_DATA = false;
+
+WIFI_GENERIC_Configuration defaultConfig;
+
+#endif // TO_LOAD_DEFAULT_CONFIG_DATA
+
+/////////// End Default Config Data /////////////
+
+
+#endif //Credentials_h
A => firmware/remote_sensors_mkr1000/include/SHT1x.h +90 -0
@@ 0,0 1,90 @@
+/**
+ * SHT1x Library
+ *
+ * Copyright 2017 Vincent Pang <wingshun.pang@gmail.com>
+ * Copyright 2009 Jonathan Oxer <jon@oxer.com.au> / <www.practicalarduino.com>
+ * Based on previous work by:
+ * Maurice Ribble: <www.glacialwanderer.com/hobbyrobotics/?p=5>
+ * Wayne ?: <ragingreality.blogspot.com/2008/01/ardunio-and-sht15.html>
+ *
+ * Manages communication with SHT1x series (SHT10, SHT11, SHT15)
+ * temperature / humidity sensors from Sensirion (www.sensirion.com).
+ */
+#ifndef SHT1x_h
+#define SHT1x_h
+
+#if (ARDUINO >= 100)
+#include <Arduino.h>
+#else
+#include <WProgram.h>
+#endif
+
+class SHT1x
+{
+ public:
+ enum class Voltage : uint8_t
+ {
+ DC_5_0v = 0
+ , DC_4_0v
+ , DC_3_5v
+ , DC_3_3v
+ , DC_3_0v
+ , DC_2_5v
+ };
+
+ enum class TemperatureMeasurementResolution : uint8_t
+ {
+ Temperature_14bit = 0
+ , Temperature_12bit
+ };
+
+ enum class HumidityMeasurementResolution : uint8_t
+ {
+ Humidity_12bit = 0
+ , Humidity_8bit
+ };
+
+ enum class ShtCommand : uint8_t
+ {
+ MeasureTemperature = 0b00000011
+ , MeasureRelativeHumidity = 0b00000101
+ , ReadStatusRegister = 0b00000111
+ , WriteStatusRegister = 0b00000110
+ , SoftReset = 0b00011110
+ };
+
+ SHT1x(uint8_t dataPin, uint8_t clockPin, Voltage voltage = Voltage::DC_5_0v);
+
+ float readHumidity() const;
+ float readTemperatureC() const;
+ float readTemperatureF() const;
+
+ private:
+ uint16_t readRawData(ShtCommand command, uint8_t dataPin, uint8_t clockPin) const;
+ bool sendCommandSHT(ShtCommand command, uint8_t dataPin, uint8_t clockPin) const;
+ bool waitForResultSHT(uint8_t dataPin) const;
+ uint16_t getData16SHT(uint8_t dataPin, uint8_t clockPin) const;
+ void skipCrcSHT(uint8_t dataPin, uint8_t clockPin) const;
+
+ double getC1(HumidityMeasurementResolution resolution) const;
+ double getC2(HumidityMeasurementResolution resolution) const;
+ double getC3(HumidityMeasurementResolution resolution) const;
+
+ double getT1(HumidityMeasurementResolution resolution) const;
+ double getT2(HumidityMeasurementResolution resolution) const;
+
+ double getD1ForC(Voltage voltage) const;
+ double getD1ForF(Voltage voltage) const;
+
+ double getD2ForC(TemperatureMeasurementResolution resolution) const;
+ double getD2ForF(TemperatureMeasurementResolution resolution) const;
+
+ const uint8_t _dataPin;
+ const uint8_t _clockPin;
+
+ const Voltage _voltage;
+ const TemperatureMeasurementResolution _tempResolution;
+ const HumidityMeasurementResolution _humidityResolution;
+};
+
+#endif
A => firmware/remote_sensors_mkr1000/include/config.h +9 -0
@@ 0,0 1,9 @@
+#define WANT_NTP 1
+#define WANT_OTA 1
+#define WANT_MDNS 1
+
+#define FIRMWARE_REVISION 1028
+
+#define RESET_INTERVAL (1000 * 3600 * 24 * 7)
+
+
A => firmware/remote_sensors_mkr1000/include/defines.h +153 -0
@@ 0,0 1,153 @@
+/****************************************************************************************************************************
+ defines.h
+ For SAMD21 MKR1000 boards using WiFi101 Modules/Shields
+
+ WiFiManager_Generic_WM_Lite is a library for the Mega, Teensy, SAM DUE, SAMD and STM32 boards
+ (https://github.com/khoih-prog/WiFiManager_Generic_Lite) to enable store Credentials in EEPROM/LittleFS for easy
+ configuration/reconfiguration and autoconnect/autoreconnect of WiFi and other services without Hardcoding.
+
+ Built by Khoi Hoang https://github.com/khoih-prog/WiFiManager_Generic_Lite
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+
+#ifndef defines_h
+#define defines_h
+
+/* Comment this out to disable prints and save space */
+#define DEBUG_WIFI_WEBSERVER_PORT Serial
+#define WIFI_GENERIC_DEBUG_OUTPUT Serial
+
+#define _WIFI_GENERIC_LOGLEVEL_ 1
+#define _WIFIMULTI_LOGLEVEL_ 1
+
+#define DRD_GENERIC_DEBUG true
+
+#if ( defined(ARDUINO_SAMD_MKR1000) || defined(ARDUINO_SAMD_MKRWIFI1010) )
+ #if defined(WIFI_GENERIC_USE_SAMD)
+ #undef WIFI_GENERIC_USE_SAMD
+ #undef WIFI_USE_SAMD
+ #endif
+ #define WIFI_GENERIC_USE_SAMD true
+ #define WIFI_USE_SAMD true
+#else
+ #error This code is intended to run only on the SAMD boards using WINC1500 and WiFi101 ! Please check your Tools->Board setting.
+#endif
+
+#if defined(WIFI_GENERIC_USE_SAMD)
+
+ #if defined(ARDUINO_SAMD_MKR1000)
+ #define BOARD_TYPE "SAMD MKR1000"
+ #elif defined(ARDUINO_SAMD_MKRWIFI1010)
+ #define BOARD_TYPE "SAMD MKRWIFI1010"
+ #else
+ #define BOARD_TYPE "SAMD Unknown"
+ #endif
+
+#endif
+
+// Start location in EEPROM to store config data. Default 0
+// Config data Size currently is 128 bytes)
+#define EEPROM_START 0
+#define EEPROM_SIZE (2 * 1024)
+
+/////////////////////////////////////////////
+
+// Add customs headers from v1.1.0
+#define USING_CUSTOMS_STYLE true
+#define USING_CUSTOMS_HEAD_ELEMENT true
+#define USING_CORS_FEATURE true
+
+/////////////////////////////////////////////
+
+#define USE_WIFI101 true
+
+#if defined(USE_WIFI_NINA)
+ #undef USE_WIFI_NINA
+#endif
+
+#define USE_WIFI_NINA false
+
+#define SHIELD_TYPE "WINC1500 using WiFi101 Library"
+#warning Using WiFi101 Library
+
+/////////////////////////////////////////////
+
+// Permit running CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET times before reset hardware
+// to permit user another chance to config. Only if Config Data is valid.
+// If Config Data is invalid, this has no effect as Config Portal will persist
+#define RESET_IF_CONFIG_TIMEOUT true
+
+// Permitted range of user-defined RETRY_TIMES_RECONNECT_WIFI between 2-5 times
+#define RETRY_TIMES_RECONNECT_WIFI 3
+
+// Permitted range of user-defined CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET between 2-100
+#define CONFIG_TIMEOUT_RETRYTIMES_BEFORE_RESET 5
+
+// Config Timeout 120s (default 60s). Applicable only if Config Data is Valid
+#define CONFIG_TIMEOUT 120000L
+
+/////////////////////////////////////////////
+
+// Permit input only one set of WiFi SSID/PWD. The other can be "NULL or "blank"
+// Default is false (if not defined) => must input 2 sets of SSID/PWD
+#define REQUIRE_ONE_SET_SSID_PW true //false
+
+// Max times to try WiFi per loop() iteration. To avoid blocking issue in loop()
+// Default 1 if not defined, and minimum 1.
+//#define MAX_NUM_WIFI_RECON_TRIES_PER_LOOP 2
+
+// Default no interval between recon WiFi if lost
+// Max permitted interval will be 10mins
+// Uncomment to use. Be careful, WiFi reconnect will be delayed if using this method
+// Only use whenever urgent tasks in loop() can't be delayed. But if so, it's better you have to rewrite your code, e.g. using higher priority tasks.
+//#define WIFI_RECON_INTERVAL 30000
+
+/////////////////////////////////////////////
+
+#define USE_DYNAMIC_PARAMETERS true
+
+/////////////////////////////////////////////
+
+#define SCAN_WIFI_NETWORKS true
+
+// To be able to manually input SSID, not from a scanned SSID lists
+#define MANUAL_SSID_INPUT_ALLOWED true
+
+// From 2-15
+#define MAX_SSID_IN_LIST 8
+
+/////////////////////////////////////////////
+
+// Optional, to use Board Name in Menu
+#define USING_BOARD_NAME true
+
+/////////////////////////////////////////////
+
+// Optional, to use Board Name in Menu
+#define USING_CONFIG_MODE_LED true
+
+#if USING_CONFIG_MODE_LED
+ #if defined(LED_BUILTIN)
+ #define CONFIG_MODE_LED LED_BUILTIN
+ #else
+ // Using default pin 13 for CONFIG_MODE_LED. To be changed as necessary
+ #define CONFIG_MODE_LED 13
+ #endif
+
+ #define LED_ON HIGH
+ #define LED_OFF LOW
+#endif
+
+/////////////////////////////////////////////
+
+#include <WiFiManager_Generic_Lite.h>
+
+#define HOST_NAME "REMOTE-WEATHER-SENSOR"
+
+#ifdef LED_BUILTIN
+ #define LED_PIN LED_BUILTIN
+#else
+ #define LED_PIN 13
+#endif
+
+#endif //defines_h
A => firmware/remote_sensors_mkr1000/include/dynamicParams.h +64 -0
@@ 0,0 1,64 @@
+/****************************************************************************************************************************
+ dynamicParams.h
+ For SAMD21 MKR1000 boards using WiFi101 Modules/Shields
+
+ WiFiManager_Generic_WM_Lite is a library for the Mega, Teensy, SAM DUE, SAMD and STM32 boards
+ (https://github.com/khoih-prog/WiFiManager_Generic_Lite) to enable store Credentials in EEPROM/LittleFS for easy
+ configuration/reconfiguration and autoconnect/autoreconnect of WiFi and other services without Hardcoding.
+
+ Built by Khoi Hoang https://github.com/khoih-prog/WiFiManager_Generic_Lite
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+
+#ifndef dynamicParams_h
+#define dynamicParams_h
+
+#include "defines.h"
+
+// USE_DYNAMIC_PARAMETERS defined in defined.h
+
+/////////////// Start dynamic Credentials ///////////////
+
+//Defined in <WiFiManager_Generic_Lite_SAMD.h>
+/**************************************
+ #define MAX_ID_LEN 5
+ #define MAX_DISPLAY_NAME_LEN 16
+
+ typedef struct
+ {
+ char id [MAX_ID_LEN + 1];
+ char displayName [MAX_DISPLAY_NAME_LEN + 1];
+ char *pdata;
+ uint8_t maxlen;
+ } MenuItem;
+**************************************/
+
+#if USE_DYNAMIC_PARAMETERS
+
+#define MAX_SERIAL_LEN 10
+
+char Hub_Serial_Number [MAX_SERIAL_LEN + 1] = "HB-54321";
+char Sensor_Serial_Number [MAX_SERIAL_LEN + 1] = "ST-54321";
+
+#define MAX_FREQ_LEN 5
+char Report_Frequency [MAX_FREQ_LEN + 1] = "60";
+
+MenuItem myMenuItems [] =
+{
+ { "hsn", "Hub Serial Number", Hub_Serial_Number, MAX_SERIAL_LEN },
+ { "ssn", "Sensor Serial Number", Sensor_Serial_Number, MAX_SERIAL_LEN },
+ { "rfq", "Report Frequency", Report_Frequency, MAX_FREQ_LEN },
+};
+
+uint16_t NUM_MENU_ITEMS = sizeof(myMenuItems) / sizeof(MenuItem); //MenuItemSize;
+
+#else
+
+MenuItem myMenuItems [] = {};
+
+uint16_t NUM_MENU_ITEMS = 0;
+
+#endif //USE_DYNAMIC_PARAMETERS
+
+
+#endif //dynamicParams_h
A => firmware/remote_sensors_mkr1000/src/main.cpp +612 -0
@@ 0,0 1,612 @@
+#include <Arduino.h>
+
+#include "defines.h"
+#include "Credentials.h"
+#include "dynamicParams.h"
+
+#include <WiFi101.h>
+#include <WiFiUdp.h>
+#include <WiFiManager_Generic_Lite.h>
+#include <MDNS_Generic.h>
+
+#include "config.h"
+
+#ifdef WANT_NTP
+#include <NTPClient.h>
+#endif /* WANT_NTP */
+#ifdef WANT_OTA
+#define NO_OTA_PORT
+#include <ArduinoOTA.h>
+#endif /* WANT_OTA */
+
+#include <StreamUtils.h>
+#include <ArduinoJson.h>
+
+#include <HTU2xD_SHT2x_Si70xx.h>
+#include "bme280.h"
+
+/****************************************************************************************************************************
+ MKR1000_WiFi101.ino
+ For SAMD21 MKR1000 boards using WiFi101 Modules/Shields
+
+ WiFiManager_Generic_WM_Lite is a library for the Mega, Teensy, SAM DUE, SAMD and STM32 boards
+ (https://github.com/khoih-prog/WiFiManager_Generic_Lite) to enable store Credentials in EEPROM/LittleFS for easy
+ configuration/reconfiguration and autoconnect/autoreconnect of WiFi and other services without Hardcoding.
+
+ Built by Khoi Hoang https://github.com/khoih-prog/WiFiManager_Generic_Lite
+ Licensed under MIT license
+ *****************************************************************************************************************************/
+
+
+WiFiManager_Generic_Lite* WiFiManager_Generic;
+
+HTU2xD_SHT2x_SI70xx ht2x(HTU2xD_SENSOR, HUMD_08BIT_TEMP_12BIT);
+bfs::Bme280 bme280(&Wire, bfs::Bme280::I2C_ADDR_PRIM);
+
+#ifdef WANT_OTA
+#define OTA_PASSWORD "7648"
+#endif /* WANT_OTA */
+
+#define DEBUG(X...) do{if(Serial)Serial.println(X);}while(0)
+#define DEBUGCHAR(X...) do{if(Serial)Serial.print(X);}while(0)
+
+
+/* by default, the value of PROJECTNAME will be used as the prefix of the devices's
+ * hostname and the configuration access point ssid.
+ */
+#define PROJECTNAME "ENVSENSOR"
+
+/* when storing data in the pseudo-eeprom of the ESP, you must specify how much space
+ * will be needed for the data stored. changing this value will likely cause existing
+ * data to be lost, so best over-estimate before going live.
+ */
+#define EEPROM_BYTES_NEEDED 50
+
+boolean sensorPresent;
+boolean bmeSensorPresent;
+
+#define SLOW 250
+#define MEDIUM 100
+#define FAST 50
+
+#define sleep(X) delay(X)
+#define ON 1
+#define OFF 0
+//
+//WiFiClient wifiClient;
+void weather_report();
+
+#define dataPin SDA
+#define clockPin SCL
+
+#define RAIN_PIN 7
+#define SPEED_PIN 6
+#define DIR_PIN A0
+
+#define RAIN_DEBOUNCE_MS 350
+
+#define SMARTWEATHER_PORT 50222
+
+IPAddress br_adr;
+
+WiFiUDP udp;
+
+String hubsn;
+String airsn;
+int reportfreq = 60;
+
+#if WANT_MDNS
+String hostname;
+WiFiUDP mdnsUdp;
+MDNS mdns(mdnsUdp);
+#endif /* WANT_MDNS */
+
+#ifdef WANT_NTP
+WiFiUDP ntpUdp;
+NTPClient timeClient(ntpUdp);
+#endif /* WANT_NTP */
+
+void rainIncrement();
+void reportRain(int increments);
+
+long ts;
+int reportcnt = 0;
+int lastobservation = 0;
+int lastreport = 0;
+void blink(int speed, int count) {
+ pinMode(16, OUTPUT);
+ for(; count > 0; count--) {
+ digitalWrite(16, ON);
+ sleep(speed);
+ digitalWrite(16, OFF);
+ sleep(speed);
+ }
+ digitalWrite(16, ON);
+}
+
+
+void heartBeatPrint(void)
+{
+ static int num = 1;
+
+ if (WiFi.status() == WL_CONNECTED)
+ Serial.print("H"); // H means connected to WiFi
+ else
+ {
+ if (WiFiManager_Generic->isConfigMode())
+ Serial.print("C"); // C means in Config Mode
+ else
+ Serial.print("F"); // F means not connected to WiFi
+ }
+
+ if (num == 80)
+ {
+ Serial.println();
+ num = 1;
+ }
+ else if (num++ % 10 == 0)
+ {
+ Serial.print(F(" "));
+ }
+}
+
+void check_status()
+{
+ static unsigned long checkstatus_timeout = 0;
+
+ //KH
+#define HEARTBEAT_INTERVAL 20000L
+ // Print hearbeat every HEARTBEAT_INTERVAL (20) seconds.
+ if ((millis() > checkstatus_timeout) || (checkstatus_timeout == 0))
+ {
+ heartBeatPrint();
+ checkstatus_timeout = millis() + HEARTBEAT_INTERVAL;
+ }
+}
+
+#if USING_CUSTOMS_STYLE
+const char NewCustomsStyle[] /*PROGMEM*/ = "<style>div,input{padding:5px;font-size:1em;}input{width:95%;}body{text-align: center;}\
+button{background-color:blue;color:white;line-height:2.4rem;font-size:1.2rem;width:100%;}fieldset{border-radius:0.3rem;margin:0px;}</style>";
+#endif
+
+void setup()
+{
+ // Debug console
+ Serial.begin(115200);
+ while (!Serial && millis() < 5000);
+
+ delay(200);
+
+ Wire.begin();
+
+ pinMode(RAIN_PIN, INPUT_PULLUP);
+ pinMode(SPEED_PIN, INPUT_PULLUP);
+ pinMode(DIR_PIN, INPUT);
+
+ Serial.print(F("\nStart MKR1000_WiFi101 on ")); Serial.print(BOARD_NAME);
+ Serial.print(F(" with ")); Serial.println(SHIELD_TYPE);
+
+#if (USE_WIFI_NINA || USE_WIFI101)
+ Serial.println(WIFIMULTI_GENERIC_VERSION);
+#endif
+ Serial.println(WIFI_MANAGER_GENERIC_LITE_VERSION);
+
+ WiFiManager_Generic = new WiFiManager_Generic_Lite();
+
+ // Optional to change default AP IP(192.168.4.1) and channel(10)
+ //WiFiManager_Generic->setConfigPortalIP(IPAddress(192, 168, 120, 1));
+ WiFiManager_Generic->setConfigPortalChannel(0);
+
+#if USING_CUSTOMS_STYLE
+ WiFiManager_Generic->setCustomsStyle(NewCustomsStyle);
+#endif
+
+#if USING_CUSTOMS_HEAD_ELEMENT
+ WiFiManager_Generic->setCustomsHeadElement("<style>html{filter: invert(10%);}</style>");
+#endif
+
+#if USING_CORS_FEATURE
+ WiFiManager_Generic->setCORSHeader("Your Access-Control-Allow-Origin");
+#endif
+
+ // Set customized DHCP HostName
+ WiFiManager_Generic->begin();
+ //Or use default Hostname "MKR1000-WIFI-XXXXXX"
+ //WiFiManager_Generic->begin();
+
+ int attempts = 0;
+
+ while ((sensorPresent = ht2x.begin()) != true && attempts < 10) //reset sensor, set heater off, set resolution, check power (sensor doesn't operate correctly if VDD < +2.25v)
+ {
+ Serial.println(F("HTU2xD/SHT2x not connected, fail or VDD < +2.25v")); //(F()) save string to flash & keeps dynamic memory free
+ delay(10);
+ attempts++;
+ }
+
+ if(sensorPresent)
+ Serial.println(F("HTU2xD/SHT2x OK"));
+
+ attempts = 0;
+ while ((bmeSensorPresent = bme280.Begin()) != true && attempts < 10) //reset sensor, set heater off, set resolution, check power (sensor doesn't operate correctly if VDD < +2.25v)
+ {
+ Serial.println(F("BME280 not connected or failed")); //(F()) save string to flash & keeps dynamic memory free
+ delay(10);
+ attempts++;
+ }
+ if(bmeSensorPresent) {
+ Serial.println(F("BME280 OK"));
+
+ bme280.ConfigStandbyTime(bfs::Bme280::STANDBY_TIME_500_MS);
+ }
+
+ if (WiFi.status() == WL_CONNECTED) {
+ hostname = HOST_NAME;
+
+#ifdef WANT_MDNS
+ // Initialize the mDNS library. You can now reach or ping this
+ // Arduino via the host name "hostname.local", provided that your operating
+ // system is mDNS/Bonjour-enabled (such as MacOS X).
+ // Always call this before any other method!
+ WIFI_GENERIC_Configuration config;
+ WiFiManager_Generic->getFullConfigData(&config);
+ if(&config != NULL) {
+ Serial.println("Board Name");
+ Serial.println(config.board_name);
+ hostname = config.board_name;
+ } else {
+ Serial.println("No Board Name!");
+ }
+
+ //hostname.toUpperCase();
+ hostname.toLowerCase();
+ hostname.replace(" ", "-");
+ hostname.replace("_", "-");
+
+ Serial.print("Registering mDNS hostname: "); Serial.println(hostname);
+ Serial.print("To access, using "); Serial.print(hostname); Serial.println(".local");
+
+ mdns.begin(WiFi.localIP(), hostname.c_str());
+
+ Serial.println(F("Registering MDNS"));
+
+#endif /* WANT_MDNS */
+
+#ifdef WANT_OTA
+ ArduinoOTA.begin(WiFi.localIP(), hostname.c_str(), (const char *) OTA_PASSWORD, InternalStorage);
+#endif /* WANT_OTA */
+
+ udp.begin(SMARTWEATHER_PORT);
+
+#ifdef WANT_NTP
+ Serial.println(F("Registering NTP client"));
+ timeClient.begin();
+#endif /* WANT_NTP */
+ }
+
+#if (LIMITED_RAM_DEVICE)
+ Serial.println("Limited RAM");
+#endif
+
+ attachInterrupt(digitalPinToInterrupt(RAIN_PIN), rainIncrement, FALLING);
+
+}
+
+int rainIncrements = 0;
+
+static unsigned long last_rain_interrupt_time = 0;
+
+void rainIncrement() {
+ unsigned long interrupt_time = millis();
+ if ((interrupt_time - last_rain_interrupt_time) > RAIN_DEBOUNCE_MS)
+ {
+ rainIncrements++;
+ last_rain_interrupt_time = interrupt_time;
+ }
+}
+
+void printWiFiStatus() {
+ // print the SSID of the network you're attached to:
+ Serial.print("SSID: ");
+ Serial.println(WiFi.SSID());
+
+ // print your WiFi 101 Shield's IP address:
+ IPAddress ip = WiFi.localIP();
+ Serial.print("IP Address: ");
+ Serial.println(ip);
+
+ // print the received signal strength:
+ long rssi = WiFi.RSSI();
+ Serial.print("signal strength (RSSI):");
+ Serial.print(rssi);
+ Serial.println(" dBm");
+#if (LIMITED_RAM_DEVICE)
+ Serial.println("Limited RAM");
+#endif
+}
+
+#if USE_DYNAMIC_PARAMETERS
+void displayCredentials()
+{
+ Serial.println(F("\nYour stored Credentials :"));
+
+ for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++)
+ {
+ Serial.print(myMenuItems[i].displayName);
+ Serial.print(F(" = "));
+ Serial.println(myMenuItems[i].pdata);
+ }
+}
+
+void displayCredentialsInLoop()
+{
+ static bool displayedCredentials = false;
+
+ if (!displayedCredentials)
+ {
+ for (int i = 0; i < NUM_MENU_ITEMS; i++)
+ {
+ if (!strlen(myMenuItems[i].pdata))
+ {
+ break;
+ }
+
+ if ( i == (NUM_MENU_ITEMS - 1) )
+ {
+ displayedCredentials = true;
+ displayCredentials();
+ }
+ }
+ }
+}
+
+#endif
+
+boolean statusNotDisplayed = true;
+
+void loop()
+{
+ WiFiManager_Generic->run();
+ check_status();
+
+ if (WiFi.status() == WL_CONNECTED) {
+ if (statusNotDisplayed) {
+ br_adr = WiFi.localIP();
+ br_adr[3] = 255;
+
+ Serial.println("Smartweather destination");
+ Serial.println(br_adr);
+ Serial.println(SMARTWEATHER_PORT);
+ String svc = hostname + "._http";
+ mdns.addServiceRecord(svc.c_str(), 80, MDNSServiceTCP);
+ printWiFiStatus();
+ statusNotDisplayed = false;
+
+ for (uint16_t i = 0; i < NUM_MENU_ITEMS; i++)
+ {
+ if(myMenuItems[i].id != NULL && strcmp("hsn", myMenuItems[i].id) == 0) {
+ Serial.print("HUB SERIAL NUMBER");
+ hubsn = myMenuItems[i].pdata;
+ }
+ if(myMenuItems[i].id != NULL && strcmp("ssn", myMenuItems[i].id) == 0) {
+ Serial.print("SENSOR SERIAL NUMBER");
+ airsn = myMenuItems[i].pdata;
+ }
+ if(myMenuItems[i].id != NULL && strcmp("rfq", myMenuItems[i].id) == 0) {
+ Serial.print("REPORT FREQUENCY");
+ String fq = myMenuItems[i].pdata;
+ reportfreq = fq.toInt();
+ Serial.print(reportfreq);
+ }
+
+ Serial.print(myMenuItems[i].displayName);
+ Serial.print(F(" = "));
+ Serial.println(myMenuItems[i].pdata);
+ }
+ }
+
+#ifdef WANT_OTA
+ ArduinoOTA.poll();
+#endif /* WANT_OTA */
+
+ // This actually runs the mDNS module. YOU HAVE TO CALL THIS PERIODICALLY,
+ // OR NOTHING WILL WORK! Preferably, call it once per loop().
+ mdns.run();
+ weather_report();
+ }
+
+#if USE_DYNAMIC_PARAMETERS
+ displayCredentialsInLoop();
+#endif
+}
+
+void weather_report() {
+ int written = 0;
+ long tsm = millis();
+
+ if(tsm > RESET_INTERVAL) {
+ delay(1000);
+ }
+
+ if((tsm/1000) > (lastreport + 30)) {
+ lastreport = millis() / 1000;
+#ifdef WANT_NTP
+ timeClient.update();
+ ts = timeClient.getEpochTime();
+#endif /* WANT_NTP */
+ blink(SLOW, 3);
+
+ {
+ Serial.println("Sending hub status");
+ Serial.println(ts);
+
+ StaticJsonDocument<200> doc;
+
+ doc["serial_number"] = hubsn;
+ doc["type"] = "hub_status";
+ doc["firmware_revision"] = FIRMWARE_REVISION;
+ doc["uptime"] = reportcnt; // millis() / 1000;
+ doc["rssi"] = WiFi.RSSI();
+ doc["timestamp"] = ts;
+
+ if (udp.beginPacket(br_adr, SMARTWEATHER_PORT)) {
+ Serial.println("Packet begun.");
+ written = serializeJson(doc, udp);
+ if (udp.endPacket())
+ Serial.println("Sent.");
+ reportcnt++;
+ } else {
+ Serial.println("Failed to send packet.");
+ }
+ }
+
+ {
+ Serial.println("Sending device status");
+
+ StaticJsonDocument<200> doc;
+
+ doc["serial_number"] = airsn;
+ doc["hub_sn"] = hubsn;
+ doc["type"] = "device_status";
+ doc["firmware_revision"] = FIRMWARE_REVISION;
+ doc["uptime"] = millis() / 1000;
+ doc["rssi"] = WiFi.RSSI();
+ doc["hub_rssi"] = WiFi.RSSI();
+ doc["voltage"] = 0.0;
+ doc["timestamp"] = ts;
+
+ if (udp.beginPacket(br_adr, SMARTWEATHER_PORT))
+ Serial.println("Packet begun.");
+ written = serializeJson(doc, udp);
+ Serial.println(written);
+ udp.println();
+ if (udp.endPacket())
+ Serial.println("Sent.");
+ }
+ }
+
+ if((tsm/1000) > (lastobservation + reportfreq)) {
+ StaticJsonDocument<400> doc;
+ blink(FAST, 2);
+ int rain = rainIncrements;
+ rainIncrements = 0;
+
+#ifdef WANT_NTP
+ ts = timeClient.getEpochTime();
+#endif /* WANT_NTP */
+ Serial.println("Sending observation");
+
+ lastobservation = (tsm/1000);
+ doc["serial_number"] = airsn;
+ doc["hub_sn"] = hubsn;
+ doc["type"] = "obs_st";
+ doc["firmware_revision"] = FIRMWARE_REVISION;
+ JsonArray obs = doc.createNestedArray("obs");
+ JsonArray obsValues = obs.createNestedArray();
+ obsValues.add(ts);
+
+ // lull
+ // avg
+ // gust
+ // direction
+ // sample interval
+ obsValues.add(0);
+ obsValues.add(0);
+ obsValues.add(0);
+ obsValues.add(0);
+ obsValues.add(60);
+
+ if(bmeSensorPresent) {
+ float t,h,p;
+
+ if(bme280.Read()) {
+
+ t = bme280.die_temp_c();
+ h = bme280.humidity_rh();
+ p = bme280.pres_pa()/100;
+
+ Serial.print("T ");
+ Serial.println(t);
+
+ Serial.print("H ");
+ Serial.println(h);
+
+ Serial.print("P ");
+ Serial.println(p);
+
+ obsValues.add(p);
+ obsValues.add(t);
+ obsValues.add(h);
+ }
+ else {
+ Serial.println("Error reading BME280 sensor.");
+ obsValues.add(0.0);
+ obsValues.add(0.0);
+ obsValues.add(0.0);
+ }
+ } else {
+ obsValues.add(0);
+ if(sensorPresent) {
+ float t,h;
+ t = ht2x.readTemperature();
+ h = ht2x.readHumidity();
+
+ Serial.print("T ");
+ Serial.println(t);
+
+ Serial.print("H ");
+ Serial.println(h);
+
+ obsValues.add(t);
+ obsValues.add(h);
+ } else {
+ obsValues.add(0);
+ obsValues.add(0);
+ }
+ }
+
+ if(sensorPresent) {
+ float t, h;
+ t = ht2x.readTemperature();
+ h = ht2x.readHumidity();
+
+ Serial.print("T ");
+ Serial.println(t);
+
+ Serial.print("H ");
+ Serial.println(h);
+
+// obsValues.add(t);
+// obsValues.add(h);
+ }
+ // ill
+ obsValues.add(0);
+ // uv
+ obsValues.add(0);
+ // rad
+ obsValues.add(0);
+ //rain prev minute
+ // employing a 0.01 inch increment gauge
+ Serial.println("rain increments");
+ Serial.println(rain);
+ obsValues.add(rain * (0.01 * 25.4));
+ // precip type
+ obsValues.add(0);
+ // lightning distance
+ obsValues.add(0);
+ // lightning count
+ obsValues.add(0);
+ // battery voltage
+ obsValues.add(0);
+
+ obsValues.add((reportfreq/60));
+
+ if(udp.beginPacket(br_adr, SMARTWEATHER_PORT))
+ Serial.println("Packet begun.");
+ written = serializeJson(doc, udp);
+ Serial.println(written);
+ udp.println();
+ if(udp.endPacket())
+ Serial.println("Sent.");
+ }
+ delay(50);
+}
No newline at end of file