commit 0df4ec243584f9626caf0aa8a3fa05cb8a8839d1 Author: MReenen Date: Mon Oct 24 22:33:02 2022 +0200 inital commit diff --git a/VersionInfo.h b/VersionInfo.h new file mode 100644 index 0000000..16e878f --- /dev/null +++ b/VersionInfo.h @@ -0,0 +1,7 @@ +#ifndef VERSIONINFO_H +#define VERSIONINFO_H + +#define BUILD_TIMESTAMP "2022-10-16T18:54:22Z" +#define CLIENT_VERSION "" + +#endif /* VERSIONINFO_H */ diff --git a/compile.sh b/compile.sh new file mode 100755 index 0000000..f4d500e --- /dev/null +++ b/compile.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +gcc src/main.c src/mqtt.c src/gpio.c \ + -lpthread -lpaho-mqtt3a -lbcm2835 \ + -o relayClient \ + -I src diff --git a/relayClient b/relayClient new file mode 100755 index 0000000..f466762 Binary files /dev/null and b/relayClient differ diff --git a/relayClient.service b/relayClient.service new file mode 100644 index 0000000..c77edf9 --- /dev/null +++ b/relayClient.service @@ -0,0 +1,26 @@ +# systemd service file to start relayClient + +[Unit] +Description=MQTT client for switching relays +#After=network.target +After=mosquitto.service + +[Service] +Type=simple +# Run as normal pi user - change to the user name you wish to run relayClient +User=mreenen +Group=mreenen +WorkingDirectory=/home/mreenen/relayClient + +ExecStart=/home/mreenen/relayClient/relayClient +# Use SIGINT to stop +KillSignal=SIGINT +# Auto restart on crash +Restart=on-failure +RestartSec=20 +# Tag things in the log +SyslogIdentifier=relayClient +#StandardOutput=syslog + +[Install] +WantedBy=multi-user.target diff --git a/src/conf.h b/src/conf.h new file mode 100644 index 0000000..9269b2c --- /dev/null +++ b/src/conf.h @@ -0,0 +1,19 @@ +#if !defined(CONF_H) +#define CONF_H + +#define ADDRESS "tcp://test.mosquitto.org:1883" +#define CLIENTID "relayClient" +#define TOPIC "coolhaven/relayClient" +#define PAYLOAD "relay1=on" +#define QOS 1 +#define TIMEOUT 10000L + +#define RECON_TIMEOUT 60 + +#if defined(_WIN32) + #define SLEEP(n) Sleep(n*10) +#else + #define SLEEP(n) usleep(n * 1000L) +#endif + +#endif diff --git a/src/gpio.c b/src/gpio.c new file mode 100644 index 0000000..1c94068 --- /dev/null +++ b/src/gpio.c @@ -0,0 +1,26 @@ +// const uint LED_PIN = PICO_DEFAULT_LED_PIN; +// gpio_init(LED_PIN); +// gpio_set_dir(LED_PIN, GPIO_OUT); +// while (true) { +// gpio_put(LED_PIN, 1); +// sleep_ms(250); +// gpio_put(LED_PIN, 0); +// sleep_ms(250); +// } + +#include +#include + + +void gpio_init(unsigned int p){ + bcm2835_init(); +} + +void gpio_set_dir(unsigned int gpio, int out){ + printf("DEBUG: set gpio pin %d to an %s\n", gpio, (out) ? "output" : "input"); + bcm2835_gpio_fsel(gpio, (out) ? BCM2835_GPIO_FSEL_OUTP : BCM2835_GPIO_FSEL_INPT); +} + +void gpio_put(unsigned int gpio, int value){ + bcm2835_gpio_write(gpio, (value) ? HIGH : LOW); +} diff --git a/src/gpio.h b/src/gpio.h new file mode 100644 index 0000000..aebeb90 --- /dev/null +++ b/src/gpio.h @@ -0,0 +1,5 @@ + + +void gpio_init(unsigned int p); +void gpio_set_dir(unsigned int gpio, int out); +void gpio_put(unsigned int gpio, int value); diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..c8faf35 --- /dev/null +++ b/src/main.c @@ -0,0 +1,126 @@ +#include +#include +#include + +#include "conf.h" + +#include "MQTTAsync.h" +#include "mqtt.h" +#include "gpio.h" + +// 4: relay displays +// 17: led strip +// 22: relay2 +// 27: relay3 + +void onConnect(void* context){ + MQTT_subscribe("coolhaven/relayClient", 1); +} + +const int gpio_pin[] = {4, 17, 22, 27, -1, -1, -1, -1, -1, -1}; +typedef enum action_e {TURN_ON, TURN_OFF, TOGGLE} action_t; +void action(int relay, action_t acct){ + if(gpio_pin[relay] == -1){ + printf("WARING: invalid relay number"); + return; + } + switch (acct) { + case TURN_ON: + printf("ACTION: turn relay%d on\n", relay); + gpio_put(gpio_pin[relay], 0); + break; + case TURN_OFF: + printf("ACTION: turn relay%d off\n", relay); + gpio_put(gpio_pin[relay], 1); + break; + case TOGGLE: + // printf("ACTION: Toggle relay%d\n", relay); + printf("WARNING: Toogle not suported yet\n"); + break; + } +} + +void relayClient(MQTTAsync_message* message){ + //message->payloadlen, (char*)message->payload + if(message->payloadlen < 6){ + printf("ERROR: playload to short\n"); + return; + } + if(!strncmp(message->payload, "relay", 5)){ + printf("ERROR: invalid playload\n"); + return; + } + char relay = *((char*)(message->payload + 5)); + if(relay < '0' && relay > '9'){ + printf("ERROR: invalid playload\n"); + return; + } + relay -= '0'; + if(message->payloadlen == 6){ + action(relay, TOGGLE); + return; + } + if(*((char*)(message->payload + 6)) != '='){ + printf("ERROR: invalid playload\n"); + return; + } + if(message->payloadlen == 9 && strncmp(message->payload + 6, "on", 2)){ + action(relay, TURN_ON); + return; + } + if(message->payloadlen == 10 && strncmp(message->payload + 6, "off", 3)){ + action(relay, TURN_OFF); + return; + } +} + +void onMessage(char* topicName, int topicLen, MQTTAsync_message* message){ + char* topic = "coolhaven/relayClient"; + char result = 1; + for (int i = 0; i < topicLen && i < strlen(topic); i++) { + if(*(topicName+i) != *(topic+i)){ + result = 0; + printf("topic corect until char %d\n", i); + break; + } + } + if(result){ + relayClient(message); + return; + } + // if(strncmp(topicName, "coolhaven/relayClient", topicLen)){ + // relayClient(message); + // return; + // } + printf("invlid topic (%.*s; %d)\n", topicLen, topicName, topicLen); + return; +} + +int main(int argc, char* argv[]){ + printf("==============================\n" + "=== relayClient ==============\n" + "==============================\n\n"); + + gpio_init(5); + for(int i=0; i<10; i++){ + if(gpio_pin[i] == 0) + continue; + gpio_set_dir(gpio_pin[i], 1); + } + + clientConf_t* client = MQTT_connect(&onConnect, &onMessage); + if(client == NULL){ + return -1; + } + + char ch = 0; + while(ch != 'Q' && ch != 'q'){ + ch = getchar(); + switch (ch) { + case 'q': + case 'Q': + MQTT_disconnect(client); + return 0; + } + } +} diff --git a/src/mqtt.c b/src/mqtt.c new file mode 100644 index 0000000..2ebe9c5 --- /dev/null +++ b/src/mqtt.c @@ -0,0 +1,162 @@ +#include +#include +#include + +#include "conf.h" + +#include "MQTTAsync.h" +#include "mqtt.h" + +clientConf_t* client; + +void reconnect(){ + int rc; + + if(client->last_reconn.t + RECON_TIMEOUT > time(NULL)){ + if(client->last_reconn.c < 10){ + printf("Wait %d seconds until reconect. reconect counter on %d\n", RECON_TIMEOUT, client->last_reconn.c); + SLEEP(RECON_TIMEOUT); + } else { + printf("Wait one hour until reconect. reconect counter on %d\n", client->last_reconn.c); + SLEEP(3600); + } + } + + printf("Reconnecting to MQTT server\n"); + rc = MQTTAsync_connect(client->client, &(client->conn_opts)); + if (rc != MQTTASYNC_SUCCESS){ + printf("ERROR: Failed to reconnect, return code %d\n", rc); + client->last_reconn.t = time(NULL); + client->last_reconn.c++; + } else { + client->last_reconn.c = 0; + } +} + +void connlost(void *context, char *cause){ + printf("\nERROR: Lost connection to MQTT\n"); + if(cause){ + printf(" cause: %s\n", cause); + } + + reconnect(); +} + +int msgarrvd(void *context, char *topicName, int topicLen, MQTTAsync_message *message){ + printf("Message arrived\n"); + printf(" topic: %s\n", topicName); + printf(" message: %.*s\n", message->payloadlen, (char*)message->payload); + + (*(client->onMessage))(topicName, topicLen, message); + + MQTTAsync_freeMessage(&message); + MQTTAsync_free(topicName); + return 1; +} + +void onConnectFailure(void* context, MQTTAsync_failureData* response){ + printf("Connect failed, rc %d\n", response->code); + reconnect(); +} + +void onConn(void* context, MQTTAsync_successData* response){ + printf("connected to MQTT server\n"); + (*(client->onConnect))(client); +} + + +clientConf_t* MQTT_connect(void (*onConnect_cb)(void* context), void (*onMessage)(char* topicName, int topicLen, MQTTAsync_message* message)){ + client = (clientConf_t*) malloc(sizeof(clientConf_t)); // keep this util i say so + int rc; + int ch; + + rc = MQTTAsync_create(&(client->client), ADDRESS, CLIENTID, MQTTCLIENT_PERSISTENCE_NONE, NULL); + if (rc != MQTTASYNC_SUCCESS){ + printf("Failed to create client, return code %d\n", rc); + free(client); + return NULL; + } + + client->onMessage = onMessage; + client->onConnect = onConnect_cb; + client->last_reconn.c = 0; + client->last_reconn.t = 0; + + rc = MQTTAsync_setCallbacks(client->client, client, &connlost, &msgarrvd, NULL); + if (rc != MQTTASYNC_SUCCESS){ + printf("Failed to set callbacks, return code %d\n", rc); + MQTTAsync_destroy(&(client->client)); + free(client); + return NULL; + } + + MQTTAsync_connectOptions conn_opts = MQTTAsync_connectOptions_initializer; + client->conn_opts = conn_opts; + client->conn_opts.keepAliveInterval = 20; + client->conn_opts.cleansession = 1; + client->conn_opts.onSuccess = onConn; + client->conn_opts.onFailure = onConnectFailure; + client->conn_opts.context = &client; + printf("connecting to MQTT server (%s)\n", ADDRESS); + rc = MQTTAsync_connect(client->client, &(client->conn_opts)); + if(rc != MQTTASYNC_SUCCESS){ + printf("Failed to start connect, return code %d\n", rc); + MQTTAsync_destroy(&(client->client)); + free(client); + return NULL; + } + + return client; +} + + + +void onDisconnectFailure(void* context, MQTTAsync_failureData* response){ + printf("Faild to discontect from MQTT, rc %d\n", response->code); + MQTTAsync_destroy(client->client); + free(client); +} + +void onDisconnect(void* context, MQTTAsync_successData* response){ + printf("disconnected from MQTT server\n"); + MQTTAsync_destroy(client->client); + free(client); +} + +void MQTT_disconnect(){ + int rc; + MQTTAsync_disconnectOptions disc_opts = MQTTAsync_disconnectOptions_initializer; + disc_opts.onSuccess = &onDisconnect; + disc_opts.onFailure = &onDisconnectFailure; + rc = MQTTAsync_disconnect(client->client, &disc_opts); + if (rc != MQTTASYNC_SUCCESS){ + printf("Failed to start disconnect, return code %d\n", rc); + MQTTAsync_destroy(client->client); + return; + } +} + + + +void onSubscribe(void* context, MQTTAsync_successData* response){ + // printf("Successful subscribed to %s\n", (char*) context); + printf("Successful subscribed\n"); +} + +void onSubscribeFailure(void* context, MQTTAsync_failureData* response){ + printf("ERROR: Subscribe failed, rc %d\n", response->code); +} + +void MQTT_subscribe(char* topic, int qos){ + int rc; + + printf("Subscribing to topic %s (QoS%d)\n", topic, qos); + MQTTAsync_responseOptions opts = MQTTAsync_responseOptions_initializer; + opts.onSuccess = &onSubscribe; + opts.onFailure = &onSubscribeFailure; + opts.context = topic; + rc = MQTTAsync_subscribe(client->client, topic, qos, &opts); + if (rc != MQTTASYNC_SUCCESS){ + printf("ERROR: Failed to start subscribe, return code %d\n", rc); + } +} diff --git a/src/mqtt.h b/src/mqtt.h new file mode 100644 index 0000000..3d46ccf --- /dev/null +++ b/src/mqtt.h @@ -0,0 +1,24 @@ +#if !defined(MQTT_H) +#define MQTT_H + +#include +#include "MQTTAsync.h" + +typedef struct clientConf_s { + MQTTAsync client; + MQTTAsync_connectOptions conn_opts; + struct lastReconn_s { + int c; + time_t t; + } last_reconn; + void (*onConnect)(void* context); + void (*onMessage)(char* topicName, int topicLen, MQTTAsync_message* message); +} clientConf_t; + + +clientConf_t* MQTT_connect(void (*onConnect)(void* context), void (*onMessage)(char* topicName, int topicLen, MQTTAsync_message* message)); +void MQTT_disconnect(); + +void MQTT_subscribe(char* topic, int qos); + +#endif diff --git a/src/test.c b/src/test.c new file mode 100644 index 0000000..239b46f --- /dev/null +++ b/src/test.c @@ -0,0 +1,35 @@ +// A simple C program to demonstrate callback +#include + +#include "mqtt.h" + + +typedef struct data_s { + int num; + void (*cb)(int num); +} data_t; + +void a(void* context){ + int num = ((clientConf_t*)context)->last_reconn.c; + printf("Hi, this is a. you gave me the number %d\n", num); +} + +clientConf_t b(int num, void* cb){ + clientConf_t data; + data.last_reconn.c = num; + data.onConnect = cb; + return data; +} + +void fire(clientConf_t* data){ + (*(data->onConnect))(data); +} + +int main(){ + printf("callback test\n"); + + clientConf_t d = b(5, &a); + + fire(&d); + +}