Initial commit.

This commit is contained in:
Dirk Jahnke 2018-11-14 08:43:50 +01:00
commit e4cb28697b
12 changed files with 899 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
.pio
.pioenvs
.piolibdeps
.clang_complete
.gcc-flags.json
.bak
.tmp

67
.travis.yml Normal file
View File

@ -0,0 +1,67 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

39
include/README Normal file
View File

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

17
platformio.ini Normal file
View File

@ -0,0 +1,17 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:heltec_wifi_kit_8]
platform = espressif8266
board = heltec_wifi_kit_8
framework = arduino
[lib_deps]
library = WifiManager, RF24, U8g2

24
src/config.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef config_h_included
#define config_h_included
#define PIN_MASTER_CLIENT_SELECT 2
#define ROLE_MASTER LOW
#define ROLE_CLIENT HIGH
#define PIN_NRF24_CE 10
#define PIN_NRF24_CSN 8
#define PIN_RELAY1 5
#define PIN_RELAY2 6
// communication protocol definitions
#define nRF_Channel 1
#define THIS_ADRESS 0 // uint8_t address of this node
#define NETWORK_ADDRESS_MASTER_SEND "1ClkM"
#define NETWORK_ADDRESS_MASTER_RECEIVE "2ClkM"
// relay based clock control behaviour
#define DEFAULT_HOLD_RELAY_MS 150
#define DEFAULT_MIN_RELAY_OFF_TIME_MS 80
#define DEFAULT_RELAY_ACTIVE_LOW true
#endif

194
src/display.cpp Normal file
View File

@ -0,0 +1,194 @@
#include <Arduino.h>
#include <U8g2lib.h>
#include <Wire.h>
#include "display.h"
// display
U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 16, /* clock=*/ 5, /* data=*/ 4);
#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH 16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ 0x00, 0xc0, // B00000000, B11000000,
0x01, 0xc0, // B00000001, B11000000,
0x01, 0xc0, // B00000001, B11000000,
0x03, 0xe0, // B00000011, B11100000,
0xf3, 0xe0, // B11110011, B11100000,
0xfe, 0xf8, // B11111110, B11111000,
0x7e, 0xff, // B01111110, B11111111,
0x33, 0x9f, // B00110011, B10011111,
0x1f, 0xfc, // B00011111, B11111100,
0x0d, 0x70, // B00001101, B01110000,
0x1b, 0xa0, // B00011011, B10100000,
0x3f, 0xe0, // B00111111, B11100000,
0x3f, 0xf0, // B00111111, B11110000,
0x7c, 0xf0, // B01111100, B11110000,
0x70, 0x70, // B01110000, B01110000,
0x00, 0x30 // B00000000, B00110000
};
void Display::setSmallTextSize(void) { u8g2.setFont(/*u8g2_font_profont10_tf*/ u8g2_font_4x6_tf ); }
int Display::getTextHeight(void) { return u8g2.getMaxCharHeight(); }
int Display::getTextCharsPerLine(void) { return u8g2.getDisplayWidth() / u8g2.getMaxCharWidth(); }
void Display::setNormalTextSize(void) { u8g2.setFont(/*u8g2_font_t0_11_tf*/ u8g2_font_mozart_nbp_tf); }
//static uint8_t getNormalTextHeight() { return Org_01.yAdvance; }
//static uint8_t getNormalTextCharsPerLine() { return 24; }
void Display::setLargeTextSize(void) { u8g2.setFont(u8g2_font_9x15B_tf); }
//static uint8_t getLargeTextHeight() { return FreeMonoBold9pt7b.yAdvance; }
//static uint8_t getLargeTextCharsPerLine() { return 12; }
Display::Display() {
currentScreen = NoScreen;
numberLogLines = 0;
setClockName("noname");
setClockSpeed("---");
setTime(5, 0);
setClockWeekday("Mon");
setClockHalted(true);
setNumberKnownClients(0);
for (int i=0; i<MAX_NUMBER_CLIENTS_DISPLAYED; ++i) setClientName(i, "---");
}
void Display::begin(void) {
u8g2.begin();
u8g2.setPowerSave(0);
setLargeTextSize();
u8g2.drawStr(0,16,"Booting FastClock");
u8g2.sendBuffer();
delay(200);
//addLogMessage("Display initialized");
}
bool Display::showBootSequenceFinished(unsigned int ms_per_step) {
static int step = 0;
static unsigned long lastStep_ms = 0;
if (step > 4) return true; // all is done; the value "4" corresponds to the number of steps in following case statement!
if (ms_per_step > millis() - lastStep_ms) return false; // do nothing, if last step execution is not long enough ago
Serial.print("showBootSequence: step="); Serial.println(step);
lastStep_ms = millis();
switch (step) {
case 0:
currentScreen = BootSequenceScreen;
break;
case 1:
u8g2.drawPixel(100, 10);
u8g2.drawPixel(102, 12);
u8g2.drawPixel(104, 14);
u8g2.drawPixel(106, 16);
u8g2.sendBuffer();
break;
case 2:
u8g2.drawLine(100, u8g2.getDisplayHeight()-1, u8g2.getDisplayWidth()-1, u8g2.getDisplayHeight()/2);
u8g2.drawCircle(u8g2.getDisplayWidth()-20, u8g2.getDisplayHeight()-10, 10, U8G2_DRAW_UPPER_LEFT | U8G2_DRAW_LOWER_RIGHT);
u8g2.sendBuffer();
break;
case 3:
u8g2.drawXBMP(60, 0, 16, 16, logo16_glcd_bmp);
u8g2.sendBuffer();
break;
case 4:
break; // empty step to be sure, that last step is displayed long enough
// if you add a step, then you need to change the condition at the beginning of this method as well (if (step > ...)
default: // do nothing
break;
}
++step;
return false;
}
void Display::showLog(void) {
currentScreen = LogScreen;
u8g2.clearBuffer();
u8g2.setDrawColor(1);
setSmallTextSize();
for (int i=0; i<MAX_NUMBER_LOG_LINES; ++i) {
u8g2.setCursor(0, i * getTextHeight());
u8g2.print(logLine[i]);
}
u8g2.sendBuffer();
}
void Display::addLogMessage(const char *message) {
if (numberLogLines >= MAX_NUMBER_LOG_LINES) {
for (int i=0; i<MAX_NUMBER_LOG_LINES-1; ++i) memcpy(logLine[i], logLine[i+1], MAX_LOG_MESSAGE_LEN);
--numberLogLines;
}
strncpy(logLine[numberLogLines++], message, MAX_LOG_MESSAGE_LEN);
if (currentScreen == LogScreen) showLog();
Serial.println(message);
}
void Display::showDashboard(void) {
static unsigned long lastDisplayUpdate_ms = 0;
currentScreen = DashboardScreen;
// avoid flickering of the display:
if (millis() - lastDisplayUpdate_ms < TIME_BETWEEN_DISPLAY_UPDATES_ms) return;
lastDisplayUpdate_ms = millis();
u8g2.clearBuffer();
u8g2.setDrawColor(1);
// ***** clock name *****
setNormalTextSize();
u8g2.setCursor(0, getTextHeight()-1);
u8g2.print(clockName);
// ****** speed *****
setNormalTextSize();
u8g2.setCursor(55, 2*getTextHeight()-1);
u8g2.print(clockSpeed);
// ***** time *****
setLargeTextSize();
u8g2.setCursor(0, u8g2.getDisplayHeight()-1);
if (clockHour < 10) u8g2.print("0");
u8g2.print(clockHour);
u8g2.print(":");
if (clockMinute < 10) u8g2.print("0");
u8g2.print(clockMinute);
// ***** halt/go *****
if (clockHalted) {
setSmallTextSize();
u8g2.setDrawColor(1);
u8g2.drawBox(55, u8g2.getDisplayHeight() - 2*getTextHeight()-3, 5*4+2, getTextHeight());
u8g2.setDrawColor(0);
u8g2.setCursor(57, u8g2.getDisplayHeight() - getTextHeight()-3);
u8g2.print("HALT");
u8g2.setDrawColor(1);
}
// **** weekday *****
setSmallTextSize();
u8g2.setCursor(60, u8g2.getDisplayHeight());
u8g2.print(clockWeekday);
// ***** # of clients *****
setSmallTextSize();
u8g2.setCursor(55, getTextHeight());
u8g2.print(numberKnownClients); u8g2.print(" -->");
// ***** client list *****
u8g2.drawVLine(79, 0, u8g2.getDisplayHeight());
for (int i=0; i<5; ++i) {
u8g2.setDrawColor(1);
u8g2.drawBox(81, i * getTextHeight(), 3*3+1, getTextHeight());
u8g2.setCursor(82, (i+1) * getTextHeight());
u8g2.setDrawColor(0);
if (i < 10) u8g2.print(0);
u8g2.print(i);
u8g2.setDrawColor(1);
u8g2.setCursor(82+3*3+1+1, (i+1) * getTextHeight());
u8g2.print(clientName[i]);
}
u8g2.sendBuffer();
}

52
src/display.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef display_h_included
#define display_h_included
// avoid flickering of the display:
#define TIME_BETWEEN_DISPLAY_UPDATES_ms 200
#define MAX_CLOCK_NAME_LEN 8
#define MAX_CLOCK_SPEED_LEN 8
#define MAX_CLOCK_WEEKDAY_LEN 4
#define MAX_NUMBER_CLIENTS_DISPLAYED 5
#define MAX_CLIENT_NAME_LEN 10
#define MAX_LOG_MESSAGE_LEN 30
#define MAX_NUMBER_LOG_LINES 5
enum ScreenMode { NoScreen, BootSequenceScreen, LogScreen, DashboardScreen };
class Display {
public:
Display();
void begin(void);
bool showBootSequenceFinished(unsigned int ms_per_step); // call this in your loop function, parameter ms_per_step controls the speed by naming the milliseconds each step should take
void showDashboard(void);
void setClockName(const char *name) { strncpy(clockName, name, MAX_CLOCK_NAME_LEN); };
void setClockSpeed(const char *speed) { strncpy(clockSpeed, speed, MAX_CLOCK_SPEED_LEN); };
void setTime(int hour, int minute) { clockHour = hour; clockMinute = minute; Serial.print("display: new time "); Serial.print(clockHour); Serial.print(":"); Serial.println(clockMinute); }
//void setClockSpeed(int _msPerModelSecond) { msPerModelSecond = _msPerModelSecond; setClockSpeed("x"); };
void setClockWeekday(const char *weekday) { strncpy(clockWeekday, weekday, MAX_CLOCK_WEEKDAY_LEN); };
void setClockHalted(bool halted) { clockHalted = halted; };
void setNumberKnownClients(int _numberKnownClients) { numberKnownClients = _numberKnownClients; };
void setClientName(int clientNumber, const char *name) { if (clientNumber < MAX_NUMBER_CLIENTS_DISPLAYED) { strncpy(clientName[clientNumber], name, MAX_CLIENT_NAME_LEN); }};
void addLogMessage(const char *message);
void showLog(void);
private:
ScreenMode currentScreen;
char clockName[MAX_CLOCK_NAME_LEN];
char clockSpeed[MAX_CLOCK_SPEED_LEN];
//int msPerModelSecond; // milliseconds each model second takes. A 500 means the clock runs twice as fast as real time.
int clockHour;
int clockMinute;
char clockWeekday[MAX_CLOCK_WEEKDAY_LEN];
bool clockHalted;
int numberKnownClients;
char clientName[MAX_NUMBER_CLIENTS_DISPLAYED][MAX_CLIENT_NAME_LEN];
char logLine[MAX_NUMBER_LOG_LINES][MAX_LOG_MESSAGE_LEN];
int numberLogLines;
void setSmallTextSize(void);
int getTextHeight(void);
int getTextCharsPerLine(void);
void setNormalTextSize(void);
void setLargeTextSize(void);
};
#endif

75
src/fastclock.cpp Normal file
View File

@ -0,0 +1,75 @@
#include <Arduino.h>
#include "fastclock.h"
void Fastclock::setClockSpeed(unsigned int _msPerModelSecond) {
msPerModelSecond = _msPerModelSecond;
char speedString[10];
snprintf(speedString, 6, "1:%1.1f", 1000.0 / msPerModelSecond);
display->setClockSpeed(speedString);
}
void Fastclock::incrementClockByMilliseconds(int amount) {
millisecond += amount;
if (millisecond >= 1000) {
unsigned int carryover = millisecond / 1000;
millisecond = millisecond % 1000;
second += carryover;
if (second >= 60) {
carryover = second / 60;
second = second % 60;
minute += carryover;
if (minute >= 60) {
carryover = minute / 60;
minute = minute % 60;
hour += carryover;
if (hour >= 24) {
carryover = hour / 24;
hour = hour % 24;
weekday += carryover;
if (weekday >= 7) {
weekday = weekday % 7;
}
}
}
}
}
/*
char timeString[51];
snprintf(timeString, 50, "%02d:%02d:%02d.%03d day %d, incBy_ms=%d", hour, minute, second, millisecond, weekday, amount);
Serial.print("*** new clock: ");
Serial.println(timeString);
*/
}
static const char *weekdayString[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
void Fastclock::loop(void) {
long newTimeTick = millis();
uint8_t oldMinute, oldDay;
if (msPerModelSecond == 0) {
Serial.println("Model speed invalid, msPerModelSecond=0");
msPerModelSecond = 500;
}
if (newTimeTick - lastTimeTickUsed < MIN_TIME_ms_BETWEEN_CLOCK_UPDATES) return;
int fastclockTimeAdvance = (newTimeTick - lastTimeTickUsed) * 1000 / msPerModelSecond;
oldMinute = minute;
oldDay = weekday;
incrementClockByMilliseconds(fastclockTimeAdvance);
lastTimeTickUsed = newTimeTick;
if (oldMinute != minute) {
Serial.print("*** minute change, tick adv="); Serial.println(fastclockTimeAdvance);
display->setTime(hour, minute);
if (oldDay != weekday) display->setClockWeekday(weekdayString[weekday]);
// time has changed, send an update via rf
// @TODO implement sending radio message
Serial.println("Would send new time");
}
}
void Fastclock::begin(void) {
lastTimeTickUsed = millis();
Serial.print("*** Setting up Fastclock, init lastSentTimeTick="); Serial.println(lastTimeTickUsed);
}

31
src/fastclock.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef fastclock_h_included
#define fastclock_h_included
#include "display.h"
#define MIN_TIME_ms_BETWEEN_CLOCK_UPDATES 200
class Fastclock {
public:
Fastclock(Display *d): display(d) { weekday=0; hour=0; minute=0; second=0; millisecond=0; msPerModelSecond=500; };
void begin(void);
void loop(void);
void incrementClockByMilliseconds(int amount);
void setClockSpeed(unsigned int msPerModelSecond);
void setTime(uint8_t hours, uint8_t minutes) { hour = hours; minute = minutes; second = 0; millisecond = 0; };
void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds) { hour = hours; minute = minutes; second = seconds; millisecond = 0; };
void setTime(uint8_t hours, uint8_t minutes, uint8_t seconds, uint16_t milliseconds) { hour = hours; minute = minutes; second = seconds; millisecond = milliseconds; };
void setWeekday(uint8_t _weekday) { weekday = _weekday; };
private:
Display *display;
unsigned long lastTimeTickUsed; // used to calculate model time
unsigned long msPerModelSecond; // 500 = twice as fast as real time
uint8_t weekday;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint16_t millisecond;
};
#endif

336
src/main.cpp Normal file
View File

@ -0,0 +1,336 @@
#include <Arduino.h>
#include <FS.h> //this needs to be first, or it all crashes and burns...
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
//needed for library
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>
#include <ArduinoJson.h>
#include <SPI.h>
#include <RF24.h>
#include "config.h"
#include "display.h"
#include "fastclock.h"
//define your default values here, if there are different values in config.json, they are overwritten.
//length should be max size + 1
char mqtt_server[40] = "";
char mqtt_port[6] = "8080";
//char blynk_token[33] = "YOUR_BLYNK_TOKEN";
//default custom static IP
char static_ip[16] = "10.0.1.56";
char static_gw[16] = "10.0.1.1";
char static_sn[16] = "255.255.255.0";
//flag for saving data
bool shouldSaveConfig = false;
RF24 radio(PIN_NRF24_CE, PIN_NRF24_CSN);
byte addresses[][6] = {NETWORK_ADDRESS_MASTER_SEND, NETWORK_ADDRESS_MASTER_RECEIVE};
// FastClock
bool isMaster = true;
Display display;
Fastclock fastclock(&display);
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
void setupWifiConnection() {
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
//**WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40);
//**WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5);
//WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 34);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wifiManager;
//set config save notify callback
wifiManager.setSaveConfigCallback(saveConfigCallback);
//set static ip
IPAddress _ip,_gw,_sn;
_ip.fromString(static_ip);
_gw.fromString(static_gw);
_sn.fromString(static_sn);
//wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
//add all your parameters here
//**wifiManager.addParameter(&custom_mqtt_server);
//**wifiManager.addParameter(&custom_mqtt_port);
//wifiManager.addParameter(&custom_blynk_token);
//reset settings - for testing
//wifiManager.resetSettings();
//set minimu quality of signal so it ignores AP's under that quality
//defaults to 8%
wifiManager.setMinimumSignalQuality();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
//wifiManager.setTimeout(120);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name
//and goes into a blocking loop awaiting configuration
Serial.println("Starting autoConnect ...");
if (!wifiManager.autoConnect("FastclockMasterAP", "password")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.reset();
delay(5000);
}
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
display.addLogMessage("WLAN connected");
//read updated parameters
//**strcpy(mqtt_server, custom_mqtt_server.getValue());
//**strcpy(mqtt_port, custom_mqtt_port.getValue());
//strcpy(blynk_token, custom_blynk_token.getValue());
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
//**json["mqtt_server"] = mqtt_server;
//**json["mqtt_port"] = mqtt_port;
//json["blynk_token"] = blynk_token;
json["ip"] = WiFi.localIP().toString();
json["gateway"] = WiFi.gatewayIP().toString();
json["subnet"] = WiFi.subnetMask().toString();
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.prettyPrintTo(Serial);
json.printTo(configFile);
configFile.close();
//end save
}
Serial.print("local ip: "); Serial.println(WiFi.localIP());
Serial.print("gateway: "); Serial.println(WiFi.gatewayIP());
Serial.print("subnet: "); Serial.println(WiFi.subnetMask());
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Starting *** FastclockMasterESP8266");
display.begin();
display.showLog();
//clean FS, for testing
//SPIFFS.format();
//read configuration from FS json
Serial.println("mounting FS...");
display.addLogMessage("mounting FS ...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
display.addLogMessage("mounting FS done");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
display.addLogMessage("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_server, json["mqtt_server"]);
//**strcpy(mqtt_port, json["mqtt_port"]);
//strcpy(blynk_token, json["blynk_token"]);
if (json["ip"]) {
Serial.print("setting custom ip from config: ");
//**strcpy(static_ip, json["ip"]);
//**strcpy(static_gw, json["gateway"]);
//**strcpy(static_sn, json["subnet"]);
Serial.println(static_ip);
/* Serial.println("converting ip");
IPAddress ip = ipFromCharArray(static_ip);
Serial.println(ip);*/
} else {
Serial.println("no custom ip in config");
}
} else {
display.addLogMessage("failed loading json");
Serial.println("failed to load json config");
}
}
}
} else {
display.addLogMessage("failed mounting FS");
Serial.println("failed to mount FS");
}
//end read
display.addLogMessage(static_ip);
display.addLogMessage(mqtt_server);
Serial.print("static ip: "); Serial.println(static_ip);
//Serial.println(blynk_token);
//**Serial.print("mqtt: "); Serial.println(mqtt_server);
// setupWifiConnection();
// setting up RF24
#if 0
display.addLogMessage("Start RF24 radio");
radio.begin();
// Open a writing and reading pipe on each radio, with opposite addresses
if (isMaster){
radio.openWritingPipe(addresses[1]);
radio.openReadingPipe(1,addresses[0]);
} else {
radio.openWritingPipe(addresses[0]);
radio.openReadingPipe(1,addresses[1]);
}
// Start the radio listening for data
radio.startListening();
#endif
fastclock.begin();
}
void loop(void)
{
if (!display.showBootSequenceFinished(1000)) {
return;
}
fastclock.loop();
display.showDashboard();
#if 0
// put your main code here, to run repeatedly:
/****************** Ping Out Role ***************************/
if (isMaster) {
radio.stopListening();
Serial.println(F("Now sending"));
unsigned long start_time = micros();
if (!radio.write(&start_time, sizeof(unsigned long))) {
Serial.println(F("failed"));
}
radio.startListening();
unsigned long started_waiting_at = micros();
boolean timeout = false;
while (!radio.available()) {
if (micros() - started_waiting_at > 200000 ) { // If waited longer than 200ms, indicate timeout and exit while loop
timeout = true;
break;
}
}
if (timeout) {
Serial.println(F("Failed, response timed out."));
} else {
unsigned long got_time;
radio.read( &got_time, sizeof(unsigned long) );
unsigned long end_time = micros();
// Spew it
Serial.print(F("Sent "));
Serial.print(start_time);
Serial.print(F(", Got response "));
Serial.print(got_time);
Serial.print(F(", Round-trip delay "));
Serial.print(end_time-start_time);
Serial.println(F(" microseconds"));
}
// Try again 1s later
delay(1000);
}
/****************** Pong Back Role ***************************/
if (!isMaster)
{
unsigned long got_time;
if( radio.available()){
// Variable for the received timestamp
while (radio.available()) { // While there is data ready
radio.read( &got_time, sizeof(unsigned long) ); // Get the payload
}
radio.stopListening(); // First, stop listening so we can talk
radio.write( &got_time, sizeof(unsigned long) ); // Send the final one back.
radio.startListening(); // Now, resume listening so we catch the next packets.
Serial.print(F("Sent response "));
Serial.println(got_time);
}
}
#endif
}
#if 0
#ifdef RF_RadioHead
if (!Datagram.init()) {
LOG(LL_ERROR, ("*** Datagram init failed"));
}
#endif
#ifdef RF_RF24
radio.begin();
if (radio.isChipConnected()) { LOG(LL_INFO, ("*** RF chip found")); }
else { LOG(LL_ERROR, ("*** ERROR: RF chip not found!")); }
radio.setChannel(1);
radio.setPALevel(RF24_PA_MAX);
radio.setDataRate(RF24_2MBPS);
radio.setAutoAck(0);
//radio.setRetries(2,15); // Optionally, increase the delay between retries & # of retries
radio.setCRCLength(RF24_CRC_8);
radio.openWritingPipe(pipes[0]);
radio.openReadingPipe(1,pipes[1]);
radio.startListening();
radio.printDetails();
// @TODO: real random seed!
//randomSeed(analogRead(0));
//randomSeed(22);
radio.powerUp();
LOG(LL_INFO, ("*** RF payload size=%d bytes", radio.getPayloadSize()));
if (radio.testCarrier() || radio.testRPD()) { LOG(LL_INFO, ("*** Carrier/RPD seen on radio")); }
if (radio.failureDetected) { LOG(LL_ERROR, ("*** Radio error detected!")); }
#endif
#endif

11
test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html