Hello
New to Arduino and C++/Sketches. Code posted below.
By testing things, breaking things, copying examples and learning I'm setting up an Arduino board to read some sensors in my greenhouse and send the values using MQTT to WeeWx, an open source weather system running on a Raspberry Pi. In this case the sensor values from the greenhouse Arduino are an addition to the main weather station feed into WeeWx which is from an all-in-one weather station.
If that station ever broke I'd be tempted to build my own around an Arduino.
At this moment an RP2040 in the greenhouse is happily sending temperature sensor data from a single DHT22 to WeeWx using MQTT. Initially my sketch locked up after a few hours but when I moved the sensor read from the loop into a function it worked fine. I've since also moved the MQTT sending into its own function.
Now, using a Uno R4 to experiment, I'm looking to expand to more sensors. I've got a couple of Dallas 1-Wire temperature sensors which will either be in addition or a replacement for the DHT22, the 1-wire advantage being I can use longer cables and have more flexibility.
My questions are:
Am I correct in saying the void function I'm using for the DHT22 sensor read is modifying a global variable - in this case dhtsensorPin2 - and isn't returning anything. I can see it works, and understand how, but wondering if what I'm thinking & saying syntax-wise is correct.
Am I also correct in thinking I should:
- Put stuff in functions.
- Each sensor, or at least by sensor type (DHT22, 1-Wire, etc) should have its own function.
- Call those functions in the loop - reading sensors & sending data stay out of the loop.
- Use naming conventions (functions, global variables etc) that make sense as to their use.
- Avoid using delay if possible.
- Use comments in the code to help myself (especially later) and anyone else reading it.
- Tidy up - once its working as we want it we should save space & make it easier to understand by removing commented out stuff we don't need.
My sketch below started as copy/paste from examples which I've then modified, so far moving the serial printing, MQTT printing and DHT22 sensor read into functions. Also lots of tidying up to do. The R4 is a "maybe other cool thing later" purchase so I'm using that to develop and test while the RP2040 does its current job in the greenhouse. I appreciate the R4 is different to the RP2040 and that I might have to use different libraries when it comes to eventually making more sensors work on the RP2040.
So from a code point of view am I on the right path?
Thanks,
Ashley
/*
This example connects to an unencrypted WiFi network.
Then it prints the MAC address of the WiFi module,
the IP address obtained, and other network details.
created 13 July 2010
by dlf (Metodo2 srl)
modified 31 May 2012
by Tom Igoe
Find the full UNO R4 WiFi Network documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples#connect-with-wpa
*/
#include "DHT.h"
#include "ArduinoMqttClient.h"
// #include "WiFiNINA.h" // this is the wifi library for the RP2040 Connect - we use the RP2040 in the greenhouse
#include "WiFiS3.h" // this is the wifi library for the Uno R4 - we use the R4 to develop & learn in comfort.
#include "arduino_secrets.h"
#define DHTPIN2 2
#define DHTTYPE DHT22
DHT dht2(DHTPIN2, DHTTYPE);
float dhtsensorPin2; // the value returned from the sensor needs to be a float value.
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
int status = WL_IDLE_STATUS; // the WiFi radio's status
WiFiClient wifiClient;
MqttClient mqttClient(wifiClient);
// MQTT broker & topics.
// Our broker is Mosquito running on the same Raspberry Pi that we are subscribing from.
// Broker and subscriber can be on the same computer. In this case Mosquito & MQTTSubscribe plugin for WeeWx weather software.
const char broker[] = "192.168.45.252";
int port = 1883;
// For info only to remind me of what MQTTSubsribe driver in WeeWx is expecting to see, and why.
// WeeWx syntax in weewx.conf on the Raspberry PI for the MQTTSubsribe driver expects to see topic/sensorname.
// The value is then mapped to the relevant WeeWx sensor. extraTemp1 etc are already pre-defined for our use.
// [[topics]]
// [[[greenhouse/generalTemperature]]]
// name = extraTemp1 // these database names are mapped to something we understand such as Greenhouse Temperature.
// const char topic[] = "greenhouse/generalTemperature" // - this is the real MQTT topic currently going to WeeWx
const char topic[] = "greenhouse/one"; // testing - we don't want this appearing in WeeWx yet so we use something WeeWx isn't watching for.
// const char topic2[] = "greenhouse/two"; // testing - we don't want this appearing in WeeWx yet so we use something WeeWx isn't watching for.
// const char topic3[] = "greenhouse/three"; // testing - we don't want this appearing in WeeWx yet so we use something WeeWx isn't watching for.
// const char dhtsensorPin2[] = "20"; // original testing value to send over MQTT before we added a sensor
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
void setup() {
//Initialize serial:
Serial.begin(9600);
// while (!Serial) {
// wait for serial port to connect. Needed for native USB port only - commented out to avoid hang when RP2040 is stand-alone
// }
// Initialise our sensor
dht2.begin();
// check for the WiFi module:
if (WiFi.status() == WL_NO_MODULE) {
Serial.println("Communication with WiFi module failed!");
// don't continue
while (true);
}
String fv = WiFi.firmwareVersion();
if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
Serial.println("Please upgrade the firmware");
}
// attempt to connect to WiFi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
// you're connected now, so print out the data:
Serial.print("You're connected to the network");
printCurrentNet();
printWifiData();
// Connect to the MQTT Broker
Serial.print("Attempting to connect to the MQTT broker: ");
Serial.println(broker);
if (!mqttClient.connect(broker, port)) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
while (1);
}
Serial.println("You're connected to the MQTT broker!");
Serial.println();
}
void loop() {
// float t = dht2.readTemperature(); // moved to its own fuction - if it works (it does!) we can delete this.
// call poll() regularly to allow the library to send MQTT keep alive which
// avoids being disconnected by the broker
mqttClient.poll();
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time a message was sent
previousMillis = currentMillis;
//record random value from A0, A1 and A2 - todo: this was in the initial MQTT example - needs removing.
// int Rvalue = analogRead(A0);
// int Rvalue2 = analogRead(A1);
// int Rvalue3 = analogRead(A2);
// Call our functions to do stuff
readdhtSensor(); // Function reads the sensor data from our DHT22
sendData(); // Function sends the sensor data via MQTT
// Serial.print("Sending message to topic: "); // moved to function 11th Oct - test
// Serial.println(topic); // moved to function 11th Oct - test
// Serial.println(dhtSensorPin2); // moved to function 11th Oct - test
// Serial.print("Sending message to topic: ");
// Serial.println(topic2);
// Serial.println(Rvalue2);
// Serial.print("Sending message to topic: ");
// Serial.println(topic2);
// Serial.println(Rvalue3);
// send message, the Print interface can be used to set the message contents
// mqttClient.beginMessage(topic); // moved to function 11th Oct - test
// mqttClient.print(dhtSensorPin2); // moved to function 11th Oct - test
// mqttClient.endMessage(); // moved to function 11th Oct - test
// mqttClient.beginMessage(topic);
// mqttClient.print(testmessage2);
// mqttClient.endMessage();
// mqttClient.beginMessage(topic3);
// mqttClient.print(Rvalue3);
// mqttClient.endMessage();
// Serial.println(); // moved to function 11th Oct - test
}
}
void readdhtSensor() {
// Wait a few seconds between measurements. The DHT sensors are a bit slow.
// delay(2000); // note: our loop has a 8000 mili (8 second) delay so do we need delay here? - testing & reading about good practices indicates no.
// Get our data from the sensor
dhtsensorPin2 = dht2.readTemperature(); // reads the temperature from the DHT22 sensor in degrees C
}
void sendData() {
// print to the serial interface - we don't need it for the MQTT to work but its easier to see if the sensor(s) are returning anyhting.
Serial.print("Sending message to topic: ");
Serial.println(topic);
Serial.println(dhtsensorPin2);
// send message, the Print interface can be used to set the message contents
mqttClient.beginMessage(topic);
mqttClient.print(dhtsensorPin2);
mqttClient.endMessage();
Serial.println();
}
void printWifiData() {
// print your board's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
// print your MAC address:
byte mac[6];
WiFi.macAddress(mac);
Serial.print("MAC address: ");
printMacAddress(mac);
}
void printCurrentNet() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print the MAC address of the router you're attached to:
byte bssid[6];
WiFi.BSSID(bssid);
Serial.print("BSSID: ");
printMacAddress(bssid);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.println(rssi);
// print the encryption type:
byte encryption = WiFi.encryptionType();
Serial.print("Encryption Type:");
Serial.println(encryption, HEX);
Serial.println();
}
void printMacAddress(byte mac[]) {
for (int i = 0; i < 6; i++) {
if (i > 0) {
Serial.print(":");
}
if (mac[i] < 16) {
Serial.print("0");
}
Serial.print(mac[i], HEX);
}
Serial.println();
}