Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed WIZnet_Library Watchdog DHT MQTT DS1820
main.cpp
- Committer:
- Geekshow
- Date:
- 2020-03-04
- Revision:
- 14:0a3c670b3862
- Parent:
- 12:bcb38c1af703
File content as of revision 14:0a3c670b3862:
#include "mbed.h"
#include "Watchdog.h"
//#include "rtos.h"
//#include "pins.h"
#include "WIZnetInterface.h"
#include "MQTTSocket.h"
#include "MQTTClient.h"
#define VERSION "v12"
// ========== PIN DEFINITIONS ============
// TODO move pin definitions into separate file
#define LED_GREEN PA_5
#define LED_ORANGE PA_1 // Don't use! Shared with D3
#define BUTTON PC_9
#define A_0 PC_0 // Analogue Input 0
#define A_1 PC_1 // Analogue Input 1
#define A_2 PC_2 // Analogue Input 2
#define A_3 PC_3 // Analogue Input 3
#define A_4 PC_4 // Analogue Input 4
#define A_5 PC_5 // Analogue Input 5
#define D_0 PA_3 // digital output D0
#define D_1 PA_2 // digital output D1
#define D_2 PA_0 // digital output D2
#define D_3 PA_1 // digital output D3
#define D_4 PB_5 // digital output D4
#define D_5 PB_6 // digital output D5
#define D_6 PA_8 // digital output D6
#define D_7 PA_9 // digital output D7
#define D_8 PA_10 // digital output D8
#define D_9 PB_7 // digital output D9
#define D_10 PA_4 // digital output D10 - SPI1 SS
#define D_11 PA_4 // digital output D11 - SPI1 MOSI
#define D_12 PA_4 // digital output D12 - SPI1 MISO
//#define D_13 PA_4 // digital output D13 - SPI1 CLK - GREEN LED
#define D_14 PB_8 // digital output D14
#define D_35 PC_6 // pin 13 on Extension
#define D_36 PC_7 // pin 14 on Extension
#define D_37 PC_8 // pin 15 on Extension (last)
// ================= *************** ==================
#define USART3_TX PC_10 // D26 - pin 4 on Extension
// ================= *************** ==================
// serial output? for uLCD
// ================= *************** ==================
// sensor inputs
#include "DS1820.h"
#define MAX_PROBES 4
#define ONEWIRE_PIN PB_11 // D30 pin 6 on UEXT // pin 8 on Extension
DS1820* probe[MAX_PROBES];
#include "DHT.h"
#define DHT_PIN PB_10 // D29 pin 5 on UEXT // pin 7 on Extension
// ================= *************** ==================
#define NODE_NAME "controller03" // TODO just define node number
#define NUM_OUTPUTS 8
DigitalOut outputs[NUM_OUTPUTS] = {D_0, D_1, D_2, D_3, D_4, D_5, D_6, D_7};
#define NUM_INPUTS 6
DigitalIn inputs[NUM_INPUTS] = {PC_0, PC_1, PC_2, PC_3, PC_4, PC_5};
bool input_state[NUM_INPUTS];
Serial pc(USART3_TX, NC); // serial debug output on D26 (pin 4 of Extension)
//Serial pc(PA_9, NC); // serial debug output on D7
//Serial xxxxxx // find a serial port for Amp/uLCD connection
DigitalIn button(BUTTON);
DigitalOut led(LED_GREEN);
DHT dht0(DHT_PIN, DHT22);
float temp[1];
float humidity[1];
Watchdog wd;
Ticker tick_30sec;
Ticker tick_5sec;
Ticker tick_1sec;
Ticker tick_500ms;
bool flag_publish;
bool flag_read_dht;
bool flag_read_ds18b20;
typedef MQTT::Client<MQTTSocket,Countdown> MClient;
const char* ONOFF[] = {"ON", "OFF"};
const char* OPENCLOSED[] = {"CLOSED", "OPEN"};
enum IO_STATE{IO_ON, IO_OFF};
uint8_t mac_addr[6]={0x00, 0x00, 0x00, 0xBE, 0xEF, 0x03}; // TODO make last byte dynamic
const char* mqtt_broker = "192.168.10.4";
//const char* mqtt_broker = "192.168.1.99";
const int mqtt_port = 1883;
unsigned long uptime_sec = 0;
int connected = -1;
void on_control_cmd(const char* topic, const char* message)
{
int new_state = 0;
pc.printf("Received CMD %s %s\r\n", topic, message);
// find out command first
if(strcmp(message, "ON") == 0) {
pc.printf("ON value requested!\r\n");
new_state = IO_ON;
}
else if(strcmp(message, "OFF") == 0) {
pc.printf("OFF value requested!\r\n");
new_state = IO_OFF;
}
else {
pc.printf("Unknown command value specified!\r\n"); // TODO return current value on no message
return;
}
// are we updating an output?
if(strncmp(topic, "output", 6) == 0) {
// find out which output to apply it to
int output_num = int(topic[6])-48;
if(output_num >= NUM_OUTPUTS) {
pc.printf("ERROR: unknown output num %d\r\n", output_num);
}
else {
// turn something on/off!
pc.printf("Output: %d updated to %s\r\n", output_num, ONOFF[new_state]);
outputs[output_num] = new_state;
flag_publish = 1; // workaround for below
// publish_value(client, topic, ONOFF[new_state], false); // needs to access client :-/
}
}
else {
pc.printf("ERROR: Couldn't parse topic: %s\r\n", topic);
}
}
int publish(MClient& client, const char* msg_type, const char* point,
const char* payload = NULL, size_t payload_len = 0,
bool retain = false, MQTT::QoS qos = MQTT::QOS1){
char topic[64];
sprintf(topic, "%s/" NODE_NAME "/%s", msg_type, point);
int ret = client.publish(topic, (void*)payload, payload_len, qos, retain);
if(ret == -1) {
pc.printf("ERROR during client.publish() = %d\r\n",ret);
}
return ret;
}
void messageArrived(MQTT::MessageData& md)
{
// MQTT callback function
MQTT::Message &message = md.message;
// copy message payload into local char array IMPROVE ME!
char* payload = new char[message.payloadlen+1];
if(!payload) // will this ever happen?
return;
memcpy(payload, message.payload, message.payloadlen);
payload[message.payloadlen]='\0';
// copy topic payload into local char array IMPROVE ME!
char* topic = new char[md.topicName.lenstring.len+1];
if(!topic){ // will this ever happen?
delete[] payload;
return;
}
memcpy(topic, md.topicName.lenstring.data, md.topicName.lenstring.len);
topic[md.topicName.lenstring.len]='\0';
pc.printf("Rcvd: %s : %s\r\n", topic, payload);
// find first delimiter in topic string
char *topics = strtok (topic,"/");
for (int tok=0; tok<2 && topics != NULL; tok++) // WARNING! hard coded 2 layer topic!
{
// pc.printf ("Topics %d: %s\r\n",tok, topics);
topics = strtok (NULL, "/");
}
on_control_cmd(topics, payload);
delete[] topic;
delete[] payload;
}
int publish_value(MClient &client, const char *topic, const char *buf, bool retain = false)
{
return publish(client, "stat", topic, buf, strlen(buf), retain);
}
void publish_outputs(MClient &client) {
for(int i=0; i<NUM_OUTPUTS; i++) {
bool output_state = outputs[i];
char topic[] = "outputx";
topic[6] = i+48;
pc.printf("Output: %s is %s\r\n", topic, ONOFF[output_state]);
connected = publish_value(client, topic, ONOFF[output_state], false);
}
}
void publish_inputs(MClient &client) {
for(int i=0; i<NUM_INPUTS; i++) {
char topic_str[8]; // long enough string for inputx
sprintf(topic_str, "input%d", i);
publish_value(client,topic_str,OPENCLOSED[input_state[i]], false);
}
}
void publish_info(MClient &client) {
// uptime
pc.printf("Uptime %d\r\n", uptime_sec);
char uptime_sec_str[12]; // long enough string for a long int
sprintf(uptime_sec_str, "%d", uptime_sec);
publish_value(client,"uptime",uptime_sec_str, false);
// alive
publish_value(client, "alive","ON", false);
}
void read_inputs(MClient &client) {
for(int i=0; i<NUM_INPUTS; i++) {
bool old_state = input_state[i]; // save old state
input_state[i] = inputs[i]; // read new value
// pc.printf("Input %d is %d\r\n", i, input_state[i]);
if(input_state[i] != old_state) {
// input has changed state
pc.printf("Input %d changed to %s\r\n", i, OPENCLOSED[input_state[i]]);
char topic_str[8]; // long enough string for inputx
sprintf(topic_str, "input%d", i);
publish_value(client,topic_str,OPENCLOSED[input_state[i]], false);
}
}
}
void read_dht(MClient &client) {
int error = dht0.readData();
if (0 == error) {
temp[0] = dht0.ReadTemperature(CELCIUS);
humidity[0] = dht0.ReadHumidity();
pc.printf("Temperature: %3.1f, Humidity: %3.1f\n", temp[0], humidity[0]);
} else {
pc.printf("DHT read error: %d\n", error);
return;
}
// convert to string and publish
char temp_str[6];
sprintf(temp_str, "%3.1f", temp[0]);
publish_value(client,"temp0",temp_str, false);
char humidity_str[6];
sprintf(humidity_str, "%3.1f", humidity[0]);
publish_value(client,"humidity0",humidity_str, false);
}
void read_ds18b20(MClient &client, int num_ds18b20) {
// Announce num of DS18B20 found
char temp_str[6];
char topic_str[6];
sprintf(temp_str, "%d", num_ds18b20);
publish_value(client,"num_ds18b20",temp_str, false);
if(num_ds18b20 > 0) {
//Start temperature conversion, wait until ready
probe[0]->convertTemperature(true, DS1820::all_devices);
for (int i = 0; i<num_ds18b20; i++) {
float temp = probe[i]->temperature();
pc.printf("Device %d returns %3.3foC\r\n", i, temp);
// convert to string and publish
sprintf(temp_str, "%3.3f", temp);
sprintf(topic_str, "probetemp%d", i);
publish_value(client,topic_str,temp_str, false);
}
}
}
int networking_init(MQTTSocket &sock, MClient &client, WIZnetInterface &wiz) {
int ret = 0;
pc.printf("\n\nNode: %s\r\n", NODE_NAME);
pc.printf("%s attempting ethernet connection...\r\n", NODE_NAME);
wiz.init(mac_addr); // resets the w5500
if (wiz.connect() == (-1)) {
pc.printf("Error getting DHCP address!!\r\n");
}
pc.printf("IP: %s\r\n", wiz.getIPAddress());
ret = sock.connect((char*)mqtt_broker,mqtt_port);
if(ret != 0){
pc.printf("failed to connect to TCP server\r\n");
return 1;
}
pc.printf("sock.connect()=%d\r\n",ret);
if(client.connect() != 0){
pc.printf("MQTT connect failed\r\n");
return -1;
}
pc.printf("client.connect()=%d\r\n",ret);
ret = client.subscribe("cmnd/" NODE_NAME "/+", MQTT::QOS1, messageArrived);
pc.printf("client.subscribe()=%d\r\n", ret);
// TODO add client ID when subscribing
// Node online message
publish_value(client, "alive","ON", false);
publish_value(client, "version", VERSION, true);
publish_value(client, "IPAddress", wiz.getIPAddress(), true);
pc.printf("Initialization done.\r\n");
return 0;
}
void every_30sec() {
// no waits or blocking routines here please!
flag_read_dht = 1;
flag_read_ds18b20 = 1;
}
void every_5sec() {
// no waits or blocking routines here please!
flag_publish = 1;
}
void every_second() {
// no waits or blocking routines here please!
uptime_sec++;
if(connected == 0) {
led = !led;
}
wd.Service(); // kick the dog before the timeout
}
void every_500ms() {
// no waits or blocking routines here please!
if(connected != 0) {
led = !led;
}
}
int main()
{
wd.Configure(20.0);
// WIZnetInterface wiz(PA_7, PA_6, PA_5, PA_4, NC); // SPI1 with no reset
WIZnetInterface wiz(PB_15, PB_14, PB_13, PB_12, PC_6); // SPI2 with D35 reset
MQTTSocket sock;
MClient client(sock);
tick_500ms.attach(&every_500ms, 0.5);
tick_1sec.attach(&every_second, 1.0);
tick_5sec.attach(&every_5sec, 5.1);
tick_30sec.attach(&every_30sec, 29.5);
//pulse all outputs
for(int i=0; i<NUM_OUTPUTS; i++) {
outputs[i] = IO_OFF;
wait(0.2);
}
// pull high all inputs
for(int i=0; i<NUM_INPUTS; i++) {
inputs[i].mode(PullUp);
}
pc.printf("\n\nNode: %s\r\n", NODE_NAME);
wd.Service(); // kick the dog before the timeout
connected = networking_init(sock, client, wiz);
// Initialize DS18B20 probe array to DS1820 objects
int num_ds18b20 = 0;
while(DS1820::unassignedProbe(ONEWIRE_PIN)) {
probe[num_ds18b20] = new DS1820(ONEWIRE_PIN);
num_ds18b20++;
if (num_ds18b20 == MAX_PROBES)
break;
}
pc.printf("DS18B20: Found %d device(s)\r\n", num_ds18b20);
while(1) {
read_inputs(client);
if(connected != 0) {
pc.printf("Restarting network....\r\n");
connected = networking_init(sock, client, wiz);
}
else {
// we're connected, do stuff!
if(flag_publish) {
publish_outputs(client);
publish_inputs(client);
publish_info(client);
flag_publish = 0;
}
else if(flag_read_dht) {
read_dht(client);
flag_read_dht = 0;
}
else if(flag_read_ds18b20) {
read_ds18b20(client, num_ds18b20);
flag_read_ds18b20 = 0;
}
}
client.yield(50); // pause a while, yawn......
}
}