Receive min/max temperature on iot device

This commit is contained in:
Reimar 2025-04-07 13:30:02 +02:00
parent 4be7977c11
commit 1fad48b7d8
Signed by: Reimar
GPG Key ID: 93549FA07F0AE268
8 changed files with 182 additions and 64 deletions

View File

@ -1,7 +1,9 @@
FILES=main.c brokers/mqtt.c brokers/amqp.c devices/temperature.c devices/display.c devices/buzzer.c device_id.c
FILES=main.c brokers/mqtt.c brokers/amqp.c devices/temperature.c devices/display.c devices/buzzer.c device_properties.c
# libgpiod version must be < 2.0
all: $(FILES)
$(CC) -lmosquitto -lrabbitmq -pthread -li2c -lgpiod $(FILES)
# apt install libmosquitto-dev librabbitmq-dev libi2c-dev libgpiod-dev libcjson-dev
all: $(FILES)
$(CC) -lmosquitto -lrabbitmq -pthread -li2c -lgpiod -lcjson $(FILES)

View File

@ -1,13 +1,20 @@
#include <rabbitmq-c/amqp.h>
#include <rabbitmq-c/tcp_socket.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "../config.h"
amqp_connection_state_t conn;
amqp_socket_t *socket;
amqp_channel_t channel = 1;
void broker_on_connect(void);
bool broker_on_message(char *exchange, char *message);
void amqp_send_message(char *queue, char *message)
{
amqp_basic_properties_t props;
@ -15,7 +22,22 @@ void amqp_send_message(char *queue, char *message)
props.content_type = amqp_literal_bytes("text/plain");
props.delivery_mode = 2;
amqp_basic_publish(conn, 1, amqp_cstring_bytes(queue), amqp_cstring_bytes(queue), 0, 0, &props, amqp_cstring_bytes(message));
amqp_basic_publish(conn, channel, amqp_cstring_bytes(queue), amqp_cstring_bytes(queue), 0, 0, &props, amqp_cstring_bytes(message));
}
void amqp_subscribe(char *queue)
{
amqp_basic_consume(conn, channel, amqp_cstring_bytes(queue), amqp_cstring_bytes("iot"), 1, 0, 0, amqp_empty_table);
}
char *amqp_bytes_to_cstring(amqp_bytes_t bytes)
{
char *str = malloc(bytes.len + 1);
memcpy(str, bytes.bytes, bytes.len);
str[bytes.len] = '\0';
return str;
}
void init_amqp(void)
@ -27,9 +49,24 @@ void init_amqp(void)
amqp_login(conn, "/", 0, 131072, 0, AMQP_SASL_METHOD_PLAIN, AMQP_USER, AMQP_PASSWORD);
amqp_channel_open(conn, 1);
amqp_channel_open(conn, channel);
broker_on_connect();
for (;;);
while (true) {
amqp_envelope_t envelope;
amqp_consume_message(conn, &envelope, NULL, 0);
char *exchange_name = amqp_bytes_to_cstring(envelope.exchange);
char *message = amqp_bytes_to_cstring(envelope.message.body);
if (broker_on_message(exchange_name, message)) {
amqp_basic_ack(conn, channel, envelope.delivery_tag, 0);
}
free(exchange_name);
free(message);
amqp_destroy_envelope(&envelope);
}
}

View File

@ -2,3 +2,5 @@ void init_amqp(void);
void amqp_send_message(char *topic, char *message);
void amqp_subscribe(char *queue);

View File

@ -1,46 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include "device_id.h"
#define DEVICE_ID_SIZE 5
char *get_device_id(void)
{
FILE *file = fopen("device_id.txt", "r");
if (!file) {
char *device_id = generate_device_id();
file = fopen("device_id.txt", "w");
fprintf(file, "%s", device_id);
fclose(file);
return device_id;
}
char *device_id = malloc(DEVICE_ID_SIZE + 1);
fgets(device_id, DEVICE_ID_SIZE + 1, file);
fclose(file);
return device_id;
}
char *generate_device_id(void)
{
char *device_id = malloc(DEVICE_ID_SIZE + 1);
for (int i = 0; i < DEVICE_ID_SIZE; i++) {
device_id[i] = 'A' + (random() % 26);
}
device_id[DEVICE_ID_SIZE] = '\0';
return device_id;
}
void destroy_device_id(char *device_id)
{
free(device_id);
}

View File

@ -1,6 +0,0 @@
char *get_device_id(void);
char *generate_device_id(void);
void destroy_device_id(char *device_id);

80
iot/device_properties.c Normal file
View File

@ -0,0 +1,80 @@
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "device_properties.h"
#define DEVICE_ID_SIZE 5
char *get_device_id(void)
{
FILE *file = fopen("device_id.txt", "r");
if (!file) {
char *device_id = generate_device_id();
file = fopen("device_id.txt", "w");
fprintf(file, "%s", device_id);
fclose(file);
return device_id;
}
char *device_id = malloc(DEVICE_ID_SIZE + 1);
fgets(device_id, DEVICE_ID_SIZE + 1, file);
fclose(file);
return device_id;
}
char *generate_device_id(void)
{
char *device_id = malloc(DEVICE_ID_SIZE + 1);
for (int i = 0; i < DEVICE_ID_SIZE; i++) {
device_id[i] = 'A' + (random() % 26);
}
device_id[DEVICE_ID_SIZE] = '\0';
return device_id;
}
void set_min_temperature(double temperature)
{
FILE *file = fopen("min_temp.txt", "w");
fprintf(file, "%lf", temperature);
fclose(file);
}
double get_min_temperature(void)
{
FILE *file = fopen("min_temp.txt", "r");
if (!file) return NAN;
double temperature = NAN;
fscanf(file, "%lf", &temperature);
fclose(file);
return temperature;
}
void set_max_temperature(double temperature)
{
FILE *file = fopen("max_temp.txt", "w");
fprintf(file, "%lf", temperature);
fclose(file);
}
double get_max_temperature(void)
{
FILE *file = fopen("max_temp.txt", "r");
if (!file) return NAN;
double temperature = NAN;
fscanf(file, "%lf", &temperature);
fclose(file);
return temperature;
}

9
iot/device_properties.h Normal file
View File

@ -0,0 +1,9 @@
char *get_device_id(void);
char *generate_device_id(void);
void set_min_temperature(double temperature);
double get_min_temperature(void);
void set_max_temperature(double temperature);
double get_max_temperature(void);

View File

@ -5,12 +5,14 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <cjson/cJSON.h>
#include "brokers/amqp.h"
#include "devices/temperature.h"
#include "devices/display.h"
#include "devices/buzzer.h"
#include "device_id.h"
#include "device_properties.h"
void *sound_alarm(void *arg)
{
@ -31,9 +33,6 @@ void *sound_alarm(void *arg)
void *watch_temperature(void *arg)
{
// TODO change
int max_temperature = 27, min_temperature = 18;
char *device_id = get_device_id();
printf("Device ID: %s\n", device_id);
@ -49,6 +48,8 @@ void *watch_temperature(void *arg)
while (true) {
// Retrieve data
double min_temperature = get_min_temperature();
double max_temperature = get_max_temperature();
double temperature = get_temperature(temp_handle);
size_t timestamp = time(NULL);
@ -76,7 +77,10 @@ void *watch_temperature(void *arg)
free(str);
// Sound alarm if applicable
if (temperature < min_temperature || temperature > max_temperature) {
if (
min_temperature != NAN && max_temperature != NAN &&
(temperature < min_temperature || temperature > max_temperature)
) {
pthread_t alarm_thread;
pthread_create(&alarm_thread, NULL, sound_alarm, NULL);
}
@ -86,17 +90,53 @@ void *watch_temperature(void *arg)
sleep(60);
}
destroy_device_id(device_id);
free(device_id);
return NULL;
}
void broker_on_connect(void)
{
amqp_subscribe("temperature-limits");
pthread_t temperature_thread;
pthread_create(&temperature_thread, NULL, watch_temperature, NULL);
}
bool broker_on_message(char *exchange, char *message)
{
cJSON *json = cJSON_Parse(message);
if (cJSON_IsInvalid(json)) goto cancel;
// Get values
cJSON *reference_id = cJSON_GetObjectItem(json, "ReferenceId");
if (!cJSON_IsString(reference_id)) goto cancel;
cJSON *min_temp = cJSON_GetObjectItem(json, "TempLow");
if (!cJSON_IsNumber(min_temp)) goto cancel;
cJSON *max_temp = cJSON_GetObjectItem(json, "TempHigh");
if (!cJSON_IsNumber(min_temp)) goto cancel;
if (strcmp(reference_id->valuestring, get_device_id()) != 0) {
goto cancel;
}
printf("Min temperature: %lf, Max temperature: %lf\n", min_temp->valuedouble, max_temp->valuedouble);
set_min_temperature(min_temp->valuedouble);
set_max_temperature(max_temp->valuedouble);
cJSON_Delete(json);
return true;
cancel:
cJSON_Delete(json);
return false;
}
int main(void)
{
srand(time(NULL));