2020-11-14 18:18:36 +00:00
|
|
|
|
//#define LOG(fmt, ...)
|
|
|
|
|
#define LOG(fmt, ...) (Serial.printf("%09llu: " fmt "\n", GetTimestamp(), ##__VA_ARGS__)); Serial.flush();
|
|
|
|
|
//#define DEBUGLOG(fmt, ...)
|
2020-11-19 09:13:55 +00:00
|
|
|
|
#define DEBUGLOG(fmt, ...) (Serial.printf("%09llu: [DEBUG] " fmt "\n", GetTimestamp(), ##__VA_ARGS__));
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
2021-06-17 13:15:37 +00:00
|
|
|
|
#define GLOBAL_VERBOSE 1//activate if the 'GREEN' status should be globally available
|
|
|
|
|
|
2020-11-19 09:13:55 +00:00
|
|
|
|
#define debounceDelay 1000 //LED shining duration
|
|
|
|
|
#define globalDelay 20000
|
2020-11-14 18:18:36 +00:00
|
|
|
|
#define alarmDelay 50
|
2021-01-22 17:13:55 +00:00
|
|
|
|
#define adcDelay 600000UL //10 minutes
|
2020-11-14 18:18:36 +00:00
|
|
|
|
#define warningDelay 333
|
2020-11-19 09:13:55 +00:00
|
|
|
|
const int MAX_PEERS = 20; //Limited due espNOW
|
2021-01-22 17:13:55 +00:00
|
|
|
|
//static const int WIFIESPNOW_KEYLEN = 16; //Limited due espNOW
|
|
|
|
|
const uint8_t key[16] = { 0 };
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
|
|
|
|
#if defined(ESP8266)
|
2020-09-04 19:41:04 +00:00
|
|
|
|
#include <ESP8266WiFi.h>
|
2021-01-22 17:13:55 +00:00
|
|
|
|
#include <Hash.h>
|
2020-11-14 18:18:36 +00:00
|
|
|
|
#elif defined(ESP32)
|
|
|
|
|
#include <WiFi.h>
|
|
|
|
|
#endif
|
2021-01-13 14:25:56 +00:00
|
|
|
|
#include <WifiEspNowBroadcast.h> //https://github.com/yoursunny/WifiEspNow
|
2020-09-04 19:41:04 +00:00
|
|
|
|
#include <Ticker.h> //Ticker Library
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
2021-06-17 13:15:37 +00:00
|
|
|
|
//version 1.1 - added originMAC
|
2020-11-19 09:13:55 +00:00
|
|
|
|
typedef struct {
|
2020-11-14 18:18:36 +00:00
|
|
|
|
char PREAMBLE1 = 'R';
|
|
|
|
|
char PREAMBLE2 = 'M';
|
|
|
|
|
uint8_t messageID[20];
|
2021-06-17 13:15:37 +00:00
|
|
|
|
char code = 'g'; // [g, y, r, X]
|
2020-11-14 18:18:36 +00:00
|
|
|
|
bool batteryWarning = false; //ToDo not implemented yet
|
2021-06-17 13:15:37 +00:00
|
|
|
|
uint8_t originMAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
2020-11-14 18:18:36 +00:00
|
|
|
|
} rm370;
|
|
|
|
|
|
2020-09-04 19:41:04 +00:00
|
|
|
|
|
2020-11-19 09:13:55 +00:00
|
|
|
|
rm370 receiveBuffer[MAX_PEERS];
|
2020-11-14 18:18:36 +00:00
|
|
|
|
rm370 transmitBuffer;
|
2020-11-19 09:13:55 +00:00
|
|
|
|
rm370 ownState;
|
2020-09-04 19:41:04 +00:00
|
|
|
|
|
2020-11-14 18:18:36 +00:00
|
|
|
|
//Remember VIL == 0.25×VIO ==> ~0,8275V
|
|
|
|
|
//Lowest voltage on LED 2,5V ==> 1,6V with level shifter
|
|
|
|
|
const uint8_t GREEN_Pin = D5; //CAUTION Vext is NOT 3.3V !!!
|
|
|
|
|
const uint8_t YELLOW_Pin = D6; //CAUTION Vext is NOT 3.3V !!!
|
|
|
|
|
const uint8_t RED_Pin = D7; //CAUTION Vext is NOT 3.3V !!!
|
|
|
|
|
const uint8_t BUZZER_Pin = D2; //CAUTION Vext is NOT 3.3V !!!
|
2021-01-22 17:13:55 +00:00
|
|
|
|
const uint8_t BAT_Pin = A0; //CAUTION Vext is NOT 1.1V !!!
|
2020-09-04 19:41:04 +00:00
|
|
|
|
|
|
|
|
|
Ticker alarmGenerator;
|
2020-11-14 18:18:36 +00:00
|
|
|
|
Ticker warningGenerator;
|
2020-11-19 09:13:55 +00:00
|
|
|
|
volatile bool alarmTrigger = false; //global
|
|
|
|
|
volatile bool warningTrigger = false; //global
|
2021-06-17 13:15:37 +00:00
|
|
|
|
volatile bool debounceTrigger = false;
|
2021-01-22 17:13:55 +00:00
|
|
|
|
//real physics workaround
|
2020-11-19 09:13:55 +00:00
|
|
|
|
volatile unsigned long globalStart = 0; //real physics workaround
|
|
|
|
|
volatile unsigned long debounceStart = 0; //real physics workaround
|
2021-01-23 15:54:54 +00:00
|
|
|
|
volatile unsigned long nowMillis = millis(); //real physics workaround
|
2021-01-22 17:13:55 +00:00
|
|
|
|
volatile unsigned long lastADCRead = 0;
|
2021-06-17 13:15:37 +00:00
|
|
|
|
volatile byte rxCounter = 0; //marker for the receive interrupt callback
|
|
|
|
|
volatile byte rxHandlePointer = 0; //marker for internal processing
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int64_t GetTimestamp() {
|
|
|
|
|
struct timeval tv;
|
|
|
|
|
gettimeofday(&tv, NULL);
|
|
|
|
|
return (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL));
|
|
|
|
|
}
|
2020-09-04 19:41:04 +00:00
|
|
|
|
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
|
|
|
|
void buzzerTone() {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//just trigger if externel trigger received
|
|
|
|
|
if (ownState.code == 'g') {
|
2020-09-04 19:41:04 +00:00
|
|
|
|
digitalWrite(BUZZER_Pin, !(digitalRead(BUZZER_Pin)));
|
|
|
|
|
}
|
2020-11-14 18:18:36 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-01-22 17:13:55 +00:00
|
|
|
|
void batteryCheck() {
|
|
|
|
|
int sensorValue = analogRead(BAT_Pin);
|
2021-06-17 13:15:37 +00:00
|
|
|
|
DEBUGLOG("AnalogRead: %i", sensorValue);
|
|
|
|
|
lastADCRead = millis();
|
|
|
|
|
int voltage = map(sensorValue, 0, 1023, 0, 5000);
|
|
|
|
|
DEBUGLOG("VoltageMap: %i mV", voltage);
|
|
|
|
|
if (voltage < 3000) {
|
|
|
|
|
ownState.batteryWarning = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ownState.batteryWarning = false;
|
|
|
|
|
}
|
2021-01-22 17:13:55 +00:00
|
|
|
|
}
|
2020-11-14 18:18:36 +00:00
|
|
|
|
void buzzerTest() {
|
|
|
|
|
LOG("Test alarm buzzer");
|
2020-11-19 09:13:55 +00:00
|
|
|
|
debounceTrigger = true;
|
2020-11-14 18:18:36 +00:00
|
|
|
|
alarmTrigger = true;
|
|
|
|
|
for (int i = 0; i < (3000 / alarmDelay); i++) {
|
|
|
|
|
buzzerTone();
|
|
|
|
|
delay(alarmDelay);
|
|
|
|
|
}
|
|
|
|
|
alarmTrigger = false;
|
2020-11-19 09:13:55 +00:00
|
|
|
|
|
2020-11-14 18:18:36 +00:00
|
|
|
|
LOG("Test warning buzzer");
|
|
|
|
|
warningTrigger = true;
|
|
|
|
|
for (int i = 0; i < (3000 / warningDelay); i++) {
|
|
|
|
|
buzzerTone();
|
|
|
|
|
delay(warningDelay);
|
|
|
|
|
}
|
|
|
|
|
warningTrigger = false;
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//Failsafe
|
2021-01-25 12:38:49 +00:00
|
|
|
|
digitalWrite(BUZZER_Pin, HIGH);
|
2020-11-19 09:13:55 +00:00
|
|
|
|
debounceTrigger = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void globalStatus() {
|
|
|
|
|
if (globalStart != 0) {
|
|
|
|
|
//reset global
|
2021-01-23 15:54:54 +00:00
|
|
|
|
if ( (nowMillis - globalStart) > globalDelay ) {
|
|
|
|
|
if (alarmGenerator.active()) {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
alarmGenerator.detach();
|
|
|
|
|
alarmTrigger = false;
|
|
|
|
|
}
|
2021-01-23 15:54:54 +00:00
|
|
|
|
if (warningGenerator.active()) {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
warningGenerator.detach();
|
|
|
|
|
warningTrigger = false;
|
|
|
|
|
}
|
|
|
|
|
globalStart = 0;
|
|
|
|
|
//Failsafe
|
2021-01-25 12:38:49 +00:00
|
|
|
|
digitalWrite(BUZZER_Pin, HIGH);
|
2020-11-19 09:13:55 +00:00
|
|
|
|
LOG("Global ended");
|
|
|
|
|
}
|
|
|
|
|
if (alarmTrigger && !alarmGenerator.active()) {
|
|
|
|
|
LOG("Global started");
|
|
|
|
|
alarmGenerator.attach(float(alarmDelay / 1000.0), buzzerTone);
|
|
|
|
|
}
|
|
|
|
|
//attach ticker
|
|
|
|
|
if (warningTrigger && !warningGenerator.active()) {
|
|
|
|
|
LOG("Global started");
|
|
|
|
|
warningGenerator.attach(float(warningDelay / 1000.0), buzzerTone);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-09-04 19:41:04 +00:00
|
|
|
|
}
|
2020-07-12 09:29:18 +00:00
|
|
|
|
|
|
|
|
|
void setup() {
|
2021-06-17 13:15:37 +00:00
|
|
|
|
pinMode(RED_Pin, INPUT_PULLUP);
|
2021-01-24 15:17:17 +00:00
|
|
|
|
pinMode(YELLOW_Pin, INPUT_PULLUP);
|
|
|
|
|
pinMode(GREEN_Pin, INPUT_PULLUP);
|
2020-09-04 19:41:04 +00:00
|
|
|
|
pinMode(BUZZER_Pin, OUTPUT);
|
2021-01-25 12:38:49 +00:00
|
|
|
|
digitalWrite(BUZZER_Pin, HIGH);
|
2020-11-14 18:18:36 +00:00
|
|
|
|
attachInterrupt(digitalPinToInterrupt(RED_Pin), IntREDCallback, FALLING);
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(YELLOW_Pin), IntYELLOWCallback, FALLING);
|
|
|
|
|
attachInterrupt(digitalPinToInterrupt(GREEN_Pin), IntGREENCallback, FALLING);
|
|
|
|
|
|
2020-11-19 09:13:55 +00:00
|
|
|
|
Serial.begin(115200);
|
2020-11-14 18:18:36 +00:00
|
|
|
|
Serial.flush();
|
|
|
|
|
delay(1000);
|
|
|
|
|
LOG("\n\nInterrupt D7,D6,D5 with Serial.print");
|
2021-06-17 13:15:37 +00:00
|
|
|
|
#if defined(GLOBAL_VERBOSE)
|
|
|
|
|
LOG("\nGlobal verbose ACTIVE");
|
|
|
|
|
#endif
|
2020-11-14 18:18:36 +00:00
|
|
|
|
if (!initCommunication()) {
|
2020-09-04 19:41:04 +00:00
|
|
|
|
ESP.restart();
|
|
|
|
|
}
|
2021-01-22 17:13:55 +00:00
|
|
|
|
batteryCheck();
|
2020-11-14 18:18:36 +00:00
|
|
|
|
buzzerTest();
|
|
|
|
|
LOG("Setup completed.\n");
|
2020-07-12 09:29:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void loop() {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//loop things
|
2021-01-23 15:54:54 +00:00
|
|
|
|
nowMillis = millis();
|
2020-11-19 09:13:55 +00:00
|
|
|
|
WifiEspNowBroadcast.loop();
|
|
|
|
|
globalStatus();
|
|
|
|
|
|
2021-01-23 15:54:54 +00:00
|
|
|
|
if ((nowMillis - lastADCRead) > adcDelay) {
|
2021-01-22 17:13:55 +00:00
|
|
|
|
batteryCheck();
|
|
|
|
|
}
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//reset debounce, as the LEDs shine a period of time
|
2021-01-23 15:54:54 +00:00
|
|
|
|
if (debounceTrigger && ((nowMillis - debounceStart) > debounceDelay)) {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
debounceTrigger = false;
|
|
|
|
|
if (ownState.code == 'r') {
|
|
|
|
|
DEBUGLOG("RED LED");
|
|
|
|
|
}
|
|
|
|
|
if (ownState.code == 'y') {
|
|
|
|
|
DEBUGLOG("YELLOW LED");
|
|
|
|
|
}
|
2021-06-17 13:15:37 +00:00
|
|
|
|
//Todo check for code 'g'
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (!(ownState.code == 'r' || ownState.code == 'y')) {
|
|
|
|
|
DEBUGLOG("GREEN LED");
|
|
|
|
|
}
|
|
|
|
|
//send own status
|
2021-06-17 13:15:37 +00:00
|
|
|
|
#if defined(GLOBAL_VERBOSE)
|
|
|
|
|
if (ownState.code == 'r' || ownState.code == 'y' || ownState.code == 'g') {
|
|
|
|
|
#else
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (ownState.code == 'r' || ownState.code == 'y') {
|
2021-06-17 13:15:37 +00:00
|
|
|
|
#endif
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//generate unique identifier
|
|
|
|
|
char messageIDString[65];
|
|
|
|
|
itoa(millis(), messageIDString, 10);
|
|
|
|
|
sha1(messageIDString, ownState.messageID);
|
|
|
|
|
transmitBuffer = ownState;
|
|
|
|
|
sendMessage();
|
|
|
|
|
}
|
2020-09-04 19:41:04 +00:00
|
|
|
|
}
|
2020-11-14 18:18:36 +00:00
|
|
|
|
|
2020-11-19 09:13:55 +00:00
|
|
|
|
//process remaining rxBuffer
|
|
|
|
|
while (rxHandlePointer != rxCounter)
|
|
|
|
|
{
|
|
|
|
|
checkMessage();
|
|
|
|
|
//shift ring buffer working pointer
|
2021-01-23 15:54:54 +00:00
|
|
|
|
if (rxHandlePointer + 1 < MAX_PEERS) {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
rxHandlePointer++;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
rxHandlePointer = 0;
|
|
|
|
|
}
|
|
|
|
|
//forward received messages
|
2021-06-17 13:15:37 +00:00
|
|
|
|
|
|
|
|
|
#if defined(GLOBAL_VERBOSE)
|
|
|
|
|
if (transmitBuffer.code == 'r' || transmitBuffer.code == 'y' || transmitBuffer.code == 'g') {
|
|
|
|
|
#else
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (transmitBuffer.code == 'r' || transmitBuffer.code == 'y') {
|
2021-06-17 13:15:37 +00:00
|
|
|
|
#endif
|
2020-11-19 09:13:55 +00:00
|
|
|
|
sendMessage();
|
|
|
|
|
}
|
2020-11-14 18:18:36 +00:00
|
|
|
|
}
|
2020-09-04 19:41:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ICACHE_RAM_ATTR void IntREDCallback() {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (!debounceTrigger) {
|
|
|
|
|
alarmTrigger = true;
|
|
|
|
|
warningTrigger = false;
|
|
|
|
|
ownState.code = 'r';
|
|
|
|
|
//real physics workaround
|
|
|
|
|
debounceTrigger = true;
|
|
|
|
|
debounceStart = millis();
|
|
|
|
|
}
|
2020-07-12 09:29:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-04 19:41:04 +00:00
|
|
|
|
ICACHE_RAM_ATTR void IntYELLOWCallback() {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (!debounceTrigger) {
|
|
|
|
|
if (!alarmTrigger) {
|
|
|
|
|
warningTrigger = true;
|
|
|
|
|
}
|
|
|
|
|
ownState.code = 'y';
|
|
|
|
|
//real physics workaround
|
|
|
|
|
debounceTrigger = true;
|
|
|
|
|
debounceStart = millis();
|
|
|
|
|
}
|
2020-07-12 09:29:18 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-04 19:41:04 +00:00
|
|
|
|
ICACHE_RAM_ATTR void IntGREENCallback() {
|
2020-11-19 09:13:55 +00:00
|
|
|
|
if (!debounceTrigger) {
|
|
|
|
|
ownState.code = 'g';
|
|
|
|
|
//real physics workaround
|
|
|
|
|
debounceTrigger = true;
|
|
|
|
|
debounceStart = millis();
|
|
|
|
|
}
|
2020-07-12 09:29:18 +00:00
|
|
|
|
}
|