Compare commits

..

4 Commits

15 changed files with 57 additions and 271 deletions

1
.gitignore vendored
View File

@@ -1,2 +1 @@
.pio .pio
data/config.json

View File

@@ -1,44 +1,13 @@
* Homeostasis * Homeostasis
Temperature, air humidity and soil humidity sensor that communicates via MQTT. The project is implemented using a Wemos D1 mini board with the following components: Temperature, air humidity and soil humidity sensor that communicates via MQTT. The project is implemented using a Wemos D1 mini board with the following addons:
- DHT22 temperature and humidity sensor - DHT11 temperature and humidity
- FC-28 soil hygrometer sensor - FC-28 soil hygrometer sensor
- Battery shield - Battery shield
- 3.7V 1000mAh Lithium battery - 3.7V 1000mAh Lithium battery
The sensor captures the data every 15 minutes and sends it to a MQTT broker and then enters deep sleep, it is important to save power as the device runs off a battery.
#+ATTR_HTML: :width 60%
[[./result.png]]
** Pinout of the board ** Pinout of the board
#+ATTR_HTML: :width 40% #+ATTR_HTML: :width 50%
[[./pinout.png]] [[./pinout.png]]
** Dependencies
- [[https://github.com/adafruit/DHT-sensor-library][Adafruit DHT sensor library]]
- [[https://github.com/adafruit/Adafruit_Sensor][Adafruit Unified Sensor Driver]]
- [[https://github.com/knolleary/pubsubclient][PubSubClient]]
- [[https://github.com/bblanchon/ArduinoJson][ArduinoJSON]]
** Deployment
The software uses the Arduino framework and the development environment of [[https://platformio.org/][PlatformIO]], which offers better tools than the Arduino IDE.
1. Upload the configuration file to the board:
#+begin_src shell
pio run -t uploadfs
#+end_src
2. Compile the project
#+begin_src shell
pio run -t compile
#+end_src
3. Upload firmware
#+begin_src shell
pio run -t upload
#+end_src

View File

@@ -1,12 +0,0 @@
{
"ssid": "",
"psk": "",
"mqtt_host": "",
"mqtt_user": "",
"mqtt_password": "",
"mqtt_port": 1883,
"mqtt_topic": "",
"device_id": "",
"sleep_time": 30,
"connection_attempts": 60
}

32
flake.lock generated
View File

@@ -1,23 +1,37 @@
{ {
"nodes": { "nodes": {
"nixpkgs": { "flake-utils": {
"locked": { "locked": {
"lastModified": 1773046814, "lastModified": 1676283394,
"narHash": "sha256-3CEw64UyzEk5QjfbcXNIl4TfmIpa2oY+duuo6aiawcU=", "narHash": "sha256-XX2f9c3iySLCw54rJ/CZs+ZK6IQy7GXNY4nSOyu2QG4=",
"owner": "NixOS", "owner": "numtide",
"repo": "nixpkgs", "repo": "flake-utils",
"rev": "0c6c0dd2469abaa216599bb19bbf77a328af6564", "rev": "3db36a8b464d0c4532ba1c7dda728f4576d6d073",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "NixOS", "owner": "numtide",
"ref": "nixos-unstable-small", "repo": "flake-utils",
"repo": "nixpkgs",
"type": "github" "type": "github"
} }
}, },
"nixpkgs": {
"locked": {
"lastModified": 1677229269,
"narHash": "sha256-awE2w6oi9rzQ8qj1lwKEDm6qIA0a239fiB+AyPjXR2w=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "7d0ed7f2e5aea07ab22ccb338d27fbe347ed2f11",
"type": "github"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"root": { "root": {
"inputs": { "inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs" "nixpkgs": "nixpkgs"
} }
} }

View File

@@ -1,25 +1,14 @@
{ {
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable-small"; description = "";
outputs = inputs.flake-utils.url = "github:numtide/flake-utils";
{ self, nixpkgs, ... }:
let outputs = { self, nixpkgs, flake-utils }:
system = "x86_64-linux"; flake-utils.lib.eachDefaultSystem
in (system:
let pkgs = nixpkgs.legacyPackages.${system}; in
{ {
devShells."${system}".default = devShell = import ./shell.nix { inherit pkgs; };
let }
pkgs = import nixpkgs { );
inherit system;
};
in
pkgs.mkShell {
packages = with pkgs; [
clang
platformio
];
shellHook = "";
};
};
} }

View File

@@ -1,24 +0,0 @@
#ifndef CONFIG_H_
#define CONFIG_H_
#include <ArduinoJson.h>
typedef struct {
const char *ssid;
const char *psk;
const char *mqtt_host;
const char *mqtt_user;
const char *mqtt_password;
const char *topic;
const char *device_id;
int mqtt_port;
unsigned long sleep_time;
} Config;
void initialize_config(Config *config, JsonDocument json);
bool load_config_file(const char *file_path, Config *config);
long minutes_to_milliseconds(int minutes);
#endif // CONFIG_H_

View File

@@ -1,10 +0,0 @@
#ifndef SENSOR_H_
#define SENSOR_H_
#include <DHT.h>
void initialize_sensor(DHT &sensor);
void read_values(DHT &sensor, float *data);
#endif // SENSOR_H_

View File

@@ -1,29 +0,0 @@
#ifndef WLAN_H
#define WLAN_H
#include "config.h"
#include <AsyncMqttClient.h>
#include <Ticker.h>
#include <WiFi.h>
static AsyncMqttClient mqtt_client;
static Ticker mqtt_connection_timer, wlan_connection_timer;
extern Config *config;
void initialize_wlan();
void initialize_mqtt();
void connect_wlan();
void connect_mqtt();
void wlan_connection_handler(WiFiEvent_t event);
void on_mqtt_disconnection(AsyncMqttClientDisconnectReason reason);
size_t construct_json(float *data, char *buffer, int buffer_size);
void mqtt_transfer(float *data);
#endif /* WLAN_H */

View File

@@ -9,13 +9,9 @@
; https://docs.platformio.org/page/projectconf.html ; https://docs.platformio.org/page/projectconf.html
[env:d1_mini] [env:d1_mini]
platform = espressif32 platform = espressif8266
board = wemos_d1_mini32 board = d1_mini
board_build.filesystem = littlefs
framework = arduino framework = arduino
monitor_filters = esp32_exception_decoder
lib_deps = lib_deps =
adafruit/DHT sensor library@^1.4.4 adafruit/DHT sensor library@^1.4.4
adafruit/Adafruit Unified Sensor@^1.1.9 adafruit/Adafruit Unified Sensor@^1.1.9
marvinroger/AsyncMqttClient@^0.9.0
bblanchon/ArduinoJson@^7.4.1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 MiB

5
shell.nix Normal file
View File

@@ -0,0 +1,5 @@
{ pkgs ? import <nixpkgs> { } }:
with pkgs;
mkShell { buildInputs = [ platformio clang ]; }

View File

@@ -1,30 +0,0 @@
#include "config.h"
#include "LittleFS.h"
void initialize_config(Config *config, JsonDocument json) {
config->ssid = strdup(json["ssid"]);
config->psk = strdup(json["psk"]);
config->mqtt_host = strdup(json["mqtt_host"]);
config->mqtt_user = strdup(json["mqtt_user"]);
config->mqtt_password = strdup(json["mqtt_password"]);
config->topic = strdup(json["mqtt_topic"]);
config->device_id = strdup(json["device_id"]);
config->mqtt_port = json["mqtt_port"];
config->sleep_time = minutes_to_milliseconds(json["sleep_time"]);
}
bool load_config_file(const char *file_path, Config *config) {
if (!LittleFS.begin())
return false;
File config_file = LittleFS.open(file_path, "r");
if (!config_file)
return false;
JsonDocument json;
DeserializationError err = deserializeJson(json, config_file);
if (err)
return false;
initialize_config(config, json);
return true;
}
long minutes_to_milliseconds(int minutes) { return (minutes * 6e4); }

View File

@@ -1,36 +1,25 @@
#include "config.h"
#include "sensor.h"
#include "wlan.h"
#include <Arduino.h> #include <Arduino.h>
#include <DHT.h> #include <DHT.h>
DHT dht(4, DHT22); #define DHTTYPE DHT11
#define DHTPIN 4
const char *config_file_path = "/config.json"; DHT dht(DHTPIN, DHTTYPE);
Config *config;
float data[2]; int fc28_pin = A0;
unsigned long previous_millis = 0; int soil_threshold = 40;
void setup() { void setup() {
Serial.begin(9600); Serial.begin(9600);
config = (Config *)malloc(sizeof(Config)); dht.begin();
if (!load_config_file(config_file_path, config))
Serial.println("ERROR: The config file could not be loaded");
initialize_wlan();
initialize_mqtt();
connect_wlan();
initialize_sensor(dht);
} }
void loop() { void loop() {
unsigned long current_millis = millis(); char buffer[200];
int analog_val = analogRead(fc28_pin);
if (current_millis - previous_millis >= config->sleep_time) { int soil_percentage = map(analog_val, 0, 1023, 0, 100);
previous_millis = current_millis; sprintf(buffer, "Temperature: %.2f°C Humidity: %.2f%% Soil humidity: %i%%",
read_values(dht, data); dht.readTemperature(), dht.readHumidity(), soil_percentage);
mqtt_transfer(data); Serial.println(buffer);
} delay(30000);
} }

View File

@@ -1,13 +0,0 @@
#include "sensor.h"
void initialize_sensor(DHT &sensor) { sensor.begin(); }
void read_values(DHT &sensor, float *data) {
float temperature = sensor.readTemperature();
float humidity = sensor.readHumidity();
Serial.println("Data fetched from the sensor");
data[0] = temperature;
data[1] = humidity;
}

View File

@@ -1,57 +0,0 @@
#include "wlan.h"
void initialize_wlan() { WiFi.onEvent(wlan_connection_handler); }
void initialize_mqtt() {
mqtt_client.onDisconnect(on_mqtt_disconnection);
mqtt_client.setServer(config->mqtt_host, config->mqtt_port);
mqtt_client.setCredentials(config->mqtt_user, config->mqtt_password);
Serial.println("MQTT initialization complete");
}
void connect_wlan() { WiFi.begin(config->ssid, config->psk); }
void connect_mqtt() {
Serial.println("Connecting to MQTT");
mqtt_client.connect();
}
void wlan_connection_handler(WiFiEvent_t event) {
Serial.printf("[WiFi-event] event: %d\n", event);
switch (event) {
case SYSTEM_EVENT_STA_GOT_IP:
Serial.println("WiFi connected");
connect_mqtt();
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi disconnected");
mqtt_connection_timer.detach();
wlan_connection_timer.once(2, connect_wlan);
break;
}
}
void on_mqtt_disconnection(AsyncMqttClientDisconnectReason reason) {
Serial.println("MQTT disconnected");
if (WiFi.isConnected()) {
mqtt_connection_timer.once(2, connect_mqtt);
}
}
size_t construct_json(float *data, char *buffer, int buffer_size) {
JsonDocument json;
json["temperature"] = data[0];
json["humidity"] = data[1];
size_t payload_size = serializeJson(json, buffer, buffer_size);
return payload_size;
}
void mqtt_transfer(float *data) {
char buffer[100];
size_t payload_size = construct_json(data, buffer, 100);
uint16_t response =
mqtt_client.publish(config->topic, 2, true, buffer, payload_size);
if (response)
Serial.println("Data transferred successfully");
}