Ready Device

This commit is contained in:
2025-09-26 16:57:05 +02:00
commit cf6b350ca8
19 changed files with 536 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
{
"folders": [
{
"path": ".."
}
],
"settings": {}
}
+37
View File
@@ -0,0 +1,37 @@
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 convention is to give header files names that end with `.h'.
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
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 the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for 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
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
+18
View File
@@ -0,0 +1,18 @@
; 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:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
upload_port = /dev/cu.usbserial-0001
lib_deps = adafruit/Adafruit AHTX0 @ ^2.0.5, knolleary/PubSubClient @ ^2.8, https://github.com/avishorp/TM1637.git
+22
View File
@@ -0,0 +1,22 @@
#include "include/clock_display.h"
ClockDisplay::ClockDisplay(uint8_t clkPin, uint8_t dioPin, uint8_t brightness)
: _clk(clkPin), _dio(dioPin), _brightness(brightness), _display(clkPin, dioPin) {}
void ClockDisplay::begin() {
_display.setBrightness(_brightness); // 0-7
_display.clear();
}
void ClockDisplay::showTime(int hour24, int minute, bool colonOn) {
uint8_t data[] = {
_display.encodeDigit((hour24 / 10) % 10),
_display.encodeDigit(hour24 % 10),
_display.encodeDigit((minute / 10) % 10),
_display.encodeDigit(minute % 10)
};
_display.setSegments(data);
_display.showNumberDecEx( (hour24/10)*1000 + (hour24%10)*100 + (minute/10)*10 + (minute%10),
colonOn ? 0b01000000 : 0,
true, 4, 0);
}
+38
View File
@@ -0,0 +1,38 @@
#include "include/dht20.h"
DHT20Sensor::DHT20Sensor() {}
bool DHT20Sensor::begin() {
if (!aht.begin()) {
Serial.println("Failed to load DHT20 sensor.");
return false;
}
Serial.println("Initialized the DHT20 sensor.");
return true;
}
void DHT20Sensor::readAndPrint() {
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp);
Serial.print("Temp: ");
Serial.print(temp.temperature);
Serial.print(" °C, Humidity: ");
Serial.print(humidity.relative_humidity);
Serial.println(" %");
}
void DHT20Sensor::read() {
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp);
_temperature = temp.temperature;
_humidity = humidity.relative_humidity;
}
float DHT20Sensor::getTemperature() const {
return _temperature;
}
float DHT20Sensor::getHumidity() const {
return _humidity;
}
+18
View File
@@ -0,0 +1,18 @@
#ifndef CLOCK_DISPLAY_H
#define CLOCK_DISPLAY_H
#include <Arduino.h>
#include <TM1637Display.h>
class ClockDisplay {
public:
ClockDisplay(uint8_t clkPin, uint8_t dioPin, uint8_t brightness = 3);
void begin();
void showTime(int hour24, int minute, bool colonOn);
private:
uint8_t _clk, _dio, _brightness;
TM1637Display _display;
};
#endif
+22
View File
@@ -0,0 +1,22 @@
#ifndef DHT20_SENSOR_H
#define DHT20_SENSOR_H
#include <Arduino.h>
#include <Adafruit_AHTX0.h>
class DHT20Sensor {
public:
DHT20Sensor();
bool begin();
void readAndPrint();
void read();
float getTemperature() const;
float getHumidity() const;
private:
Adafruit_AHTX0 aht;
float _temperature;
float _humidity;
};
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef MQ2_SENSOR_H
#define MQ2_SENSOR_H
#include <Arduino.h>
class MQ2Sensor {
public:
MQ2Sensor(uint8_t digitalPin);
void begin();
void read();
bool isGasDetected() const;
void printStatus();
private:
uint8_t _digitalPin;
bool _gasDetected;
};
#endif
+27
View File
@@ -0,0 +1,27 @@
#ifndef MQTT_CLIENT_H
#define MQTT_CLIENT_H
#include <Arduino.h>
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
class MQTTClientWrapper {
public:
MQTTClientWrapper(const char* broker, uint16_t port, const char* user, const char* password);
void begin();
void loop();
void publishSensorData(float temp, float humidity, bool gas);
private:
const char* _broker;
uint16_t _port;
const char* _user;
const char* _password;
WiFiClient _wifiClient;
PubSubClient _client;
void reconnect();
};
#endif
+23
View File
@@ -0,0 +1,23 @@
#ifndef TIME_SYNC_H
#define TIME_SYNC_H
#include <Arduino.h>
#include <time.h>
class TimeSync {
public:
// tzExample: "CET-1CEST,M3.5.0,M10.5.0/3" for Europe/Berlin
void begin(const char* tzString = "CET-1CEST,M3.5.0,M10.5.0/3");
bool isTimeSet() const;
void update();
int hour() const;
int minute() const;
time_t now() const;
private:
bool _timeSet = false;
mutable tm _tmCache{};
void refreshLocalTM() const;
};
#endif
+19
View File
@@ -0,0 +1,19 @@
#ifndef WIFI_CONNECTION_H
#define WIFI_CONNECTION_H
#include <Arduino.h>
#include <ESP8266WiFi.h>
class WiFiConnection {
public:
WiFiConnection(const char* ssid, const char* password);
void begin();
bool isConnected();
void printIP();
private:
const char* _ssid;
const char* _password;
};
#endif
+77
View File
@@ -0,0 +1,77 @@
#include <Arduino.h>
#include "include/dht20.h"
#include "include/mq2.h"
#include "include/wifi_connection.h"
#include "include/mqtt_client.h"
#include "include/clock_display.h"
#include "include/time_sync.h"
#include "secrets/secrets.h"
DHT20Sensor dht20;
MQ2Sensor mq2(D5);
WiFiConnection wifi(WIFI_SSID, WIFI_PASSWORD);
MQTTClientWrapper mqtt(MQTT_BROKER, 1883, MQTT_USER, MQTT_PASSWORD);
TimeSync timeSync;
ClockDisplay clockDisp(/*CLK=*/D6, /*DIO=*/D7, /*brightness=*/4);
unsigned long lastDHTPublish = 0;
const unsigned long dhtInterval = 60000;
unsigned long lastClockUpdate = 0;
bool colon = false;
void setup() {
Serial.begin(9600);
delay(100);
if (!dht20.begin()) {
Serial.println("Sensor init failed, check wiring!");
while (1) delay(100);
}
mq2.begin();
delay(1000);
wifi.begin();
mqtt.begin();
timeSync.begin("CET-1CEST,M3.5.0,M10.5.0/3");
clockDisp.begin();
}
void loop() {
if (!wifi.isConnected()) {
Serial.println("Lost WiFi, reconnecting...");
wifi.begin();
}
mqtt.loop();
unsigned long nowMs = millis();
if (nowMs - lastDHTPublish >= dhtInterval) {
dht20.read();
mq2.read();
float temp = dht20.getTemperature() - 0.3f;
float hum = dht20.getHumidity();
bool gas = mq2.isGasDetected();
mqtt.publishSensorData(temp, hum, gas);
lastDHTPublish = nowMs;
}
if (nowMs - lastClockUpdate >= 1000) {
lastClockUpdate = nowMs;
colon = !colon;
if (timeSync.isTimeSet()) {
int h = timeSync.hour();
int m = timeSync.minute();
clockDisp.showTime(h, m, colon);
} else {
clockDisp.showTime(0, 0, colon);
}
}
delay(50);
}
+25
View File
@@ -0,0 +1,25 @@
#include "include/mq2.h"
MQ2Sensor::MQ2Sensor(uint8_t digitalPin) : _digitalPin(digitalPin) {}
void MQ2Sensor::begin() {
pinMode(_digitalPin, INPUT);
Serial.println("Initialized the MQ-2 sensor.");
}
void MQ2Sensor::read() {
int state = digitalRead(_digitalPin);
_gasDetected = (state == LOW);
}
bool MQ2Sensor::isGasDetected() const {
return _gasDetected;
}
void MQ2Sensor::printStatus() {
if (isGasDetected()) {
Serial.println("Gas/Smoke detected!");
} else {
Serial.println("Clean");
}
}
+37
View File
@@ -0,0 +1,37 @@
#include "include/mqtt_client.h"
MQTTClientWrapper::MQTTClientWrapper(const char* broker, uint16_t port, const char* user, const char* password)
: _broker(broker), _port(port), _user(user), _password(password), _client(_wifiClient) {}
void MQTTClientWrapper::begin() {
_client.setServer(_broker, _port);
}
void MQTTClientWrapper::loop() {
if (!_client.connected()) {
reconnect();
}
_client.loop();
}
void MQTTClientWrapper::publishSensorData(float temp, float humidity, bool gas) {
if (_client.connected()) {
_client.publish("home/esp8266-1/temp", String(temp, 1).c_str());
_client.publish("home/esp8266-1/humidity", String(humidity, 1).c_str());
_client.publish("home/esp8266-1/gas", gas ? "1" : "0");
}
}
void MQTTClientWrapper::reconnect() {
while (!_client.connected()) {
Serial.print("Connecting to MQTT...");
if (_client.connect("ESP8266Client", _user, _password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(_client.state());
Serial.println(" try again in 5s");
delay(5000);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef SECRETS_H
#define SECRETS_H
#define WIFI_SSID "SSID"
#define WIFI_PASSWORD "WIFI_PASSWORD"
#define MQTT_BROKER "LOCAL_IP_TO_MQTT_SERVER"
#define MQTT_USER "MQTT_USER"
#define MQTT_PASSWORD "MQTT_PASSWORD"
#endif
+43
View File
@@ -0,0 +1,43 @@
#include "include/time_sync.h"
void TimeSync::begin(const char* tzString) {
configTime(0, 0, "pool.ntp.org", "time.nist.gov", "time.google.com");
setenv("TZ", tzString, 1);
tzset();
for (int i = 0; i < 50; i++) {
time_t t = time(nullptr);
if (t > 1600000000) {
_timeSet = true;
break;
}
delay(100);
}
}
bool TimeSync::isTimeSet() const {
time_t t = time(nullptr);
return (t > 1600000000);
}
void TimeSync::update() {
}
void TimeSync::refreshLocalTM() const {
time_t t = time(nullptr);
localtime_r(&t, &_tmCache);
}
int TimeSync::hour() const {
refreshLocalTM();
return _tmCache.tm_hour;
}
int TimeSync::minute() const {
refreshLocalTM();
return _tmCache.tm_min;
}
time_t TimeSync::now() const {
return time(nullptr);
}
+35
View File
@@ -0,0 +1,35 @@
#include "include/wifi_connection.h"
WiFiConnection::WiFiConnection(const char* ssid, const char* password)
: _ssid(ssid), _password(password) {}
void WiFiConnection::begin() {
Serial.print("Connecting to WiFi: ");
Serial.println(_ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(_ssid, _password);
int retries = 0;
while (WiFi.status() != WL_CONNECTED && retries < 20) {
delay(500);
Serial.print(".");
retries++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi connected!");
printIP();
} else {
Serial.println("\nFailed to connect to WiFi.");
}
}
bool WiFiConnection::isConnected() {
return WiFi.status() == WL_CONNECTED;
}
void WiFiConnection::printIP() {
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
}
+11
View File
@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner 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 PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html