initial commit

This commit is contained in:
Svante Kaiser 2023-11-02 13:14:34 +03:00
commit d46849736f
13 changed files with 669 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

58
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,58 @@
{
"files.associations": {
"algorithm": "cpp",
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"cerrno": "cpp",
"climits": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"map": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"ios": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"locale": "cpp",
"new": "cpp",
"ostream": "cpp",
"queue": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"cstdbool": "cpp",
"typeinfo": "cpp"
}
}

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

21
platformio.ini Normal file
View File

@ -0,0 +1,21 @@
; 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:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
check_skip_packages = yes
monitor_speed = 115200
debug_tool = esp-prog
board_build.partitions = no_ota.csv
lib_deps =
adafruit/Adafruit NeoPixel@^1.11.0
ottowinter/AsyncMqttClient-esphome@^0.8.6

0
src/config/config.h Normal file
View File

50
src/infra/mqtt.cpp Normal file
View File

@ -0,0 +1,50 @@
#include <Arduino.h>
#include "infra/mqtt.h"
void connectToMqtt() {
Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
uint16_t packetIdSub = mqttClient.subscribe("esp32/led", 0);
Serial.print("Subscribing at QoS 0, packetId: ");
Serial.println(packetIdSub);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
if (WiFi.isConnected()) {
xTimerStart(mqttReconnectTimer, 0);
}
}
void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
Serial.print(" qos: ");
Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void onMqttPublish(uint16_t packetId) {
Serial.println("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
void sendDataToMQTT(int flatNumber) {
char num_char[3];
sprintf(num_char, "%d", flatNumber);
mqttClient.publish("/digitum/out/flat_number", 2, true, num_char);
}

18
src/infra/mqtt.h Normal file
View File

@ -0,0 +1,18 @@
#ifndef INFRA_MQTT_H
#define INFRA_MQTT_H
#include <HTTPClient.h>
#include <AsyncMqttClient.h>
AsyncMqttClient mqttClient;
TimerHandle_t mqttReconnectTimer;
void connectToMqtt();
void onMqttConnect(bool sessionPresent);
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason);
void onMqttSubscribe(uint16_t packetId, uint8_t qos);
void onMqttUnsubscribe(uint16_t packetId);
void onMqttPublish(uint16_t packetId);
void sendDataToMQTT(int flatNumber);
#endif // INFRA_MQTT_H

214
src/main.cpp Normal file
View File

@ -0,0 +1,214 @@
#include <Arduino.h>
#include <ETH.h>
#include <SPI.h>
#include <SD.h>
#include <HTTPClient.h>
#include <IPAddress.h>
#include <AsyncMqttClient.h>
#include "infra/mqtt.h"
#include "utils/print.h"
#include "stateMachine.h"
#define LEDS_PIN 32
#define DRY_CONT_PIN 15
#define DOOR_SENS_PIN 114
#define DATA_PIN 12
#define DATA_PERIOD 240 // microseconds
#define PRINT_RAW_SIGNAL_FLAG 0
/*
* ETH_CLOCK_GPIO0_IN - default: external clock from crystal oscillator
* ETH_CLOCK_GPIO0_OUT - 50MHz clock from internal APLL output on GPIO0 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO16_OUT - 50MHz clock from internal APLL output on GPIO16 - possibly an inverter is needed for LAN8720
* ETH_CLOCK_GPIO17_OUT - 50MHz clock from internal APLL inverted output on GPIO17 - tested with LAN8720
*/
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
// Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
#define ETH_POWER_PIN 16
// Type of the Ethernet PHY (LAN8720 or TLK110)
#define ETH_TYPE ETH_PHY_LAN8720
// I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
#define ETH_ADDR 1
// Pin# of the I²C clock signal for the Ethernet PHY
#define ETH_MDC_PIN 23
// Pin# of the I²C IO signal for the Ethernet PHY
#define ETH_MDIO_PIN 18
#define NRST 5
#define MQTT_HOST IPAddress(192, 168, 1, 173)
#define MQTT_PORT 1883
uint32_t lastMillis;
uint64_t lastMicros;
static bool eth_connected = false;
TimerHandle_t ethReconnectTimer;
void WiFiEvent(WiFiEvent_t event)
{
#if ESP_IDF_VERSION_MAJOR > 3
switch (event) {
case ARDUINO_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case ARDUINO_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case ARDUINO_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
connectToMqtt();
break;
case ARDUINO_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case ARDUINO_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#elif
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
// set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
#endif
}
void connectEth() {
pinMode(NRST, OUTPUT);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
digitalWrite(NRST, 0);
delay(200);
digitalWrite(NRST, 1);
delay(200);
ETH.begin(ETH_ADDR,
ETH_POWER_PIN,
ETH_MDC_PIN,
ETH_MDIO_PIN,
ETH_TYPE,
ETH_CLK_MODE);
}
void testClient(const char * host, uint16_t port)
{
Serial.print("\nconnecting to ");
Serial.println(host);
WiFiClient client;
if (!client.connect(host, port)) {
Serial.println("connection failed");
return;
}
client.printf("GET / HTTP/1.1\r\nHost: %s\r\n\r\n", host);
while (client.connected() && !client.available());
while (client.available()) {
Serial.write(client.read());
}
Serial.println("closing connection\n");
client.stop();
}
void setup() {
Serial.begin(115200);
WiFi.onEvent(WiFiEvent);
connectEth();
mqttReconnectTimer = xTimerCreate("mqttTimer", pdMS_TO_TICKS(2000), pdFALSE, (void*)0, reinterpret_cast<TimerCallbackFunction_t>(connectToMqtt));
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
mqttClient.onSubscribe(onMqttSubscribe);
mqttClient.onUnsubscribe(onMqttUnsubscribe);
//mqttClient.onMessage(onMqttMessage);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
pinMode(DATA_PIN, INPUT);
pinMode(DRY_CONT_PIN, OUTPUT);
digitalWrite(DRY_CONT_PIN, 0);
delay(2000);
digitalWrite(DRY_CONT_PIN, 1);
delay(2000);
digitalWrite(DRY_CONT_PIN, 0);
delay(2000);
}
void loop() {
if (lastMicros < micros()) {
data = digitalRead(DATA_PIN);
updateStateMachine(data);
if (PRINT_RAW_SIGNAL_FLAG)
printf("{}", data);
lastMillis = micros() + DATA_PERIOD;
}
if (eth_connected) {
if (lastMillis < millis()) {;
lastMillis = millis() + 3000;
}
}
}

100
src/stateMachine.cpp Normal file
View File

@ -0,0 +1,100 @@
#include "stateMachine.h"
void updateStateMachine(int data) {
switch (currentState) {
case NOT_CONNECTED:
if (data == 0) {
// Stay in the NOT_CONNECTED state
} else if (data == 1) {
currentState = CONNECTED;
println("connected");
}
break;
case CONNECTED:
if (data == 0) {
countZeros++;
if (countZeros >= NOT_CONNECTED_THRESHOLD) {
currentState = NOT_CONNECTED;
println("not connected");
resetCounters();
}
} else if (data == 1) {
if (countZeros >= INITIALIZING_CALL_THRESHOLD) {
currentState = RECEIVING_DATA;
println("receiving data");
resetCounters();
}
}
break;
case RECEIVING_DATA:
if (data != previousData) {
if (previousData == HIGH) {
dataLength++;
}
signalDuration = 0;
} else {
signalDuration++;
}
previousData = data;
if (data == 0) {
countOnes = 0;
countZeros++;
if (countZeros >= DATA_RECEIVED_THESHOLD) {
println("| data length: ", dataLength);
println("| flat: ", dataLength/2);
//sendDataToMQTT(dataLength/2);
currentState = DATA_RECEIVED;
println("data received");
resetCounters();
}
} else if (data == 1) {
countZeros = 0;
countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED;
println("connected");
resetCounters();
}
}
break;
case DATA_RECEIVED:
if (data == 0) {
countZeros++;
if (countZeros >= CALL_ENDED_THRESHOLD) {
currentState = CALL_ENDED;
println("call ended");
resetCounters();
}
} else if (data == 1) {
countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED;
println("connected");
resetCounters();
}
break;
}
case CALL_ENDED:
if (data == 0) {
countZeros++;
if (countZeros >= NOT_CONNECTED_THRESHOLD) {
currentState = NOT_CONNECTED;
println("not connected");
resetCounters();
}
} else if (data == 1) {
countOnes++;
if (countOnes >= CONNECTED_THRESHOLD) {
currentState = CONNECTED;
println("connected");
resetCounters();
}
break;
}
}
}

33
src/stateMachine.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef STATE_MACHINE_H
#define STATE_MACHINE_H
#include <Arduino.h>
#include "utils/print.cpp"
#define CONNECTED_THRESHOLD 50000
#define NOT_CONNECTED_THRESHOLD 50000
#define INITIALIZING_CALL_THRESHOLD 15000
#define DATA_RECEIVED_THESHOLD 30000
#define CALL_ENDED_THRESHOLD 10000
enum State {
NOT_CONNECTED,
CONNECTED,
RECEIVING_DATA,
DATA_RECEIVED,
CALL_ENDED
};
int data = 0;
State currentState = NOT_CONNECTED;
int countZeros = 0;
int countOnes = 0;
int previousData = 0;
int dataLength = 0;
int signalDuration = 0;
void resetCounters();
void updateStateMachine(int data);
#endif // STATE_MACHINE_H

77
src/utils/print.cpp Normal file
View File

@ -0,0 +1,77 @@
#include <Arduino.h>
#include "utils/print.h"
void print() {
// Empty function to terminate recursion
}
// Overloaded function to print a single value
template <typename T>
void print(T value) {
Serial.print(value);
}
// Recursive function to print multiple values
template <typename T, typename... Args>
void print(T value, Args... args) {
Serial.print(value);
print(args...); // Recursively call print for the remaining arguments
}
// Function to print a newline
void println() {
Serial.println();
}
// Overloaded function to print a single value and a newline
template <typename T>
void println(T value) {
Serial.println(value);
}
// Recursive function to print multiple values and a newline
template <typename T, typename... Args>
void println(T value, Args... args) {
Serial.print(value);
println(args...); // Recursively call println for the remaining arguments
}
// Convenience functions for easy usage
template <typename... Args>
void print(Args... args) {
print(args...);
}
template <typename... Args>
void println(Args... args) {
println(args...);
}
String fstring(const char* format) {
String result = format;
return result;
}
template <typename... Args>
String fstring(const char* format, Args... args) {
String result = "";
while (*format) {
if (*format == '{' && *(format + 1) == '}' && sizeof...(args) > 0) {
result += String(args...);
format += 2; // Skip the "{}" in the format string
} else {
result += *format;
format++;
}
}
return result;
}
void printf(const char* format) {
Serial.print(fstring(format));
}
template <typename... Args>
void printf(const char* format, Args... args) {
Serial.print(fstring(format, args...));
}

44
src/utils/print.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef UTILS_PRINT_H
#define UTILS_PRINT_H
#include <Arduino.h>
void print();
// Overloaded function to print a single value
template <typename T>
void print(T value);
// Recursive function to print multiple values
template <typename T, typename... Args>
void print(T value, Args... args);
// Function to print a newline
void println();
// Overloaded function to print a single value and a newline
template <typename T>
void println(T value);
// Recursive function to print multiple values and a newline
template <typename T, typename... Args>
void println(T value, Args... args);
// Convenience functions for easy usage
template <typename... Args>
void print(Args... args);
template <typename... Args>
void println(Args... args);
String fstring(const char* format);
template <typename... Args>
String fstring(const char* format, Args... args);
void printf(const char* format);
template <typename... Args>
void printf(const char* format, Args... args);
#endif // UTILS_PRINT_H