From cd006b9357bcb632a2d4539c086fb93ca6ae23c6 Mon Sep 17 00:00:00 2001
From: guowenxue <guowenxue@gmail.com>
Date: Mon, 17 Nov 2025 23:37:49 +0800
Subject: [PATCH] Update lightd to support DS18B20 and TLS2561
---
project/lightd/etc/lightd.service | 15 ++
project/lightd/config.c | 27 +++-
project/lightd/etc/lightd.conf | 23 ++-
project/lightd/config.h | 5
project/lightd/hal/ds18b20.h | 31 +++++
project/lightd/lightd.c | 125 ++++++++++++++++----
project/lightd/hal/ds18b20.c | 118 +++++++++++++++++++
project/lightd/hal/gpio.c | 7 -
8 files changed, 302 insertions(+), 49 deletions(-)
diff --git a/project/lightd/config.c b/project/lightd/config.c
index f9c646c..4f2b261 100644
--- a/project/lightd/config.c
+++ b/project/lightd/config.c
@@ -41,6 +41,7 @@
logger = &ctx->logger;
hwinfo = &ctx->hwinfo;
mqtt = &ctx->mqtt;
+ mqtt->userdata = (void *)hwinfo;
ini = iniparser_load(conf_file);
if( !ini )
@@ -94,7 +95,25 @@
*| parser hardware module configuration |
*+------------------------------------------------------+*/
- /* parser GPIO output pins */
+ /* DS18B20 temperature sensor status */
+ hwinfo->ds18b20=iniparser_getint(ini, "hardware:ds18b20", 0);
+ if( !hwinfo->ds18b20 )
+ log_warn("Parser DS18B20 temperature module disabled\n");
+ else
+ log_info("Parser DS18B20 temperature module enabled\n");
+
+ /* TSL2561 lux sensor status */
+ hwinfo->tsl2561=iniparser_getint(ini, "hardware:tsl2561", 0);
+ if( !hwinfo->tsl2561)
+ log_warn("Parser TSL2561 lux sensor module disabled\n");
+ else
+ log_info("Parser TSL2561 lux sensor module enabled\n");
+
+ /* TSL2561 lux sensor threshold value */
+ hwinfo->lux_threshold = iniparser_getdouble(ini, "hardware:lux_threshold", 0.1);
+ log_info("parser LUX enable and threshold value set be [%.03f]\n", hwinfo->lux_threshold);
+
+ /* parser GPIO output pins for relay */
if( !(str=iniparser_getstring(ini, "hardware:gpio_outpin", NULL)) )
{
log_warn("parser no GPIO output pins\n");
@@ -108,7 +127,7 @@
hwinfo->light_intval = iniparser_getint(ini, "hardware:light_intval", 20);
log_info("parser relay controled light interval time [%d]\n", hwinfo->light_intval);
- /* parser GPIO input pins */
+ /* parser GPIO input pins for infrared */
if( !(str=iniparser_getstring(ini, "hardware:gpio_inpin", NULL)) )
{
log_warn("parser no GPIO input pins\n");
@@ -118,10 +137,6 @@
parser_gpio_info(_TYPE_INPUT, &hwinfo->gpio, (char *)str);
log_info("parser [%d] GPIO input pins\n", hwinfo->gpio.incnt);
}
-
- hwinfo->lux_threshold = iniparser_getdouble(ini, "hardware:lux_threshold", 0.1);
- log_info("parser LUX enable and threshold value set be [%.03f]\n", hwinfo->lux_threshold);
-
/*+------------------------------------------------------+
*| parser broker settings |
diff --git a/project/lightd/config.h b/project/lightd/config.h
index 5bff2bc..85f47ff 100644
--- a/project/lightd/config.h
+++ b/project/lightd/config.h
@@ -28,7 +28,8 @@
typedef struct mqtt_ctx_s
{
- char devid[32]; /* device ID */
+ char devid[32]; /* device ID */
+ void *userdata; /* user data pointer */
/* Broker settings */
char host[128]; /* MQTT broker server name */
@@ -61,6 +62,8 @@
gpio_t gpio; /* gpio information */
int light_intval; /* light on interval */
float lux_threshold;/* lux threshold value */
+ int ds18b20; /* ds18b20 enable or not */
+ int tsl2561; /* tsl2561 enable or not */
} hwinfo_t;
typedef struct iotd_ctx_s
diff --git a/project/lightd/etc/lightd.conf b/project/lightd/etc/lightd.conf
index 13494b9..f877998 100644
--- a/project/lightd/etc/lightd.conf
+++ b/project/lightd/etc/lightd.conf
@@ -4,16 +4,23 @@
# 树莓派连接的外设信息,使能或相关硬件连接的Pin管脚
[hardware]
-# 红外感应灯GPIO输入控制, 格式: {名称:BCM编码:控制电平}
-# Indoor(#16)<->(black/gray) Hallway(#18)<->(yellow/red)
-gpio_inpin={infrared_indoor:23:1},{infrared_hallway:24:1}
+# 是否使能 DS18B20 温湿度传感器模块,0:禁用 1:使能
+ds18b20=1
-# 继电器GPIO输出控制, 格式: {名称:BCM编码:控制电平}
-# Relay(1) <-> #35 Relay(2) <-> #37
-gpio_outpin={light_indoor:19:1},{light_hallway:26:1}
+# 是否使能 TSL2561 光强传感器模块,0:禁用 1:使能
+tsl2561=1
# TSL2561 光强传感器光强阈值
lux_threshold=0.10
+
+# 红外传感器(有人时输出高电平), 格式: {名称:BCM编码:控制电平}
+# Indoor(#16)<->(black/gray) Hallway(#12)<->(yellow/red)
+# 测试延时: while true; do gpioget gpiochip0 18; sleep 1; done
+gpio_inpin={infrared_indoor:23:1},{infrared_hallway:18:1}
+
+# 继电器GPIO输出控制, 格式: {名称:BCM编码:控制电平}
+# Relay(1) <-> #35 Relay(2) <-> #37
+gpio_outpin={light_indoor:19:1},{light_hallway:26:1}
# 红外探测到人后,继电器控制灯亮的时长
light_intval=15
@@ -24,7 +31,7 @@
# 日志记录文件
file=/var/log/lightd.log
-# 日志级别: 0:ERROR 1:WARN 2:INFO 3:DEBUG 4:TRACE
+# 日志级别: 0:ERROR 1:WARN 2:INFO 3:DEBUG 4:TRACE
level=2
# 日志回滚大小
@@ -62,7 +69,7 @@
[subsciber]
-# mosquitto_sub -h weike-iot.com -p 2262 -u "gu8wq8mfj1gadkyh6yo5" -t "v1/devices/me/rpc/request/+"
+# mosquitto_sub -h weike-iot.com -p 2262 -u "gu8wq8mfj1gadkyh6yo5" -t "v1/devices/me/rpc/request/+"
# {"method":"setValue","params":{"device":"lightIndoor","status":true}}
# {"method":"setValue","params":{"device":"lightHallway","status":true}}
subTopic="v1/devices/me/rpc/request/+"
diff --git a/project/lightd/etc/lightd.service b/project/lightd/etc/lightd.service
new file mode 100644
index 0000000..4129fd7
--- /dev/null
+++ b/project/lightd/etc/lightd.service
@@ -0,0 +1,15 @@
+[Unit]
+Description=RaspberryPi Auto light program Service
+After=network.target
+
+[Service]
+Type=simple
+ExecStartPre=/bin/rm -f /tmp/.lightd.pid /var/log/lightd.log
+ExecStart=/usr/bin/lightd -c /etc/lightd.conf
+
+Restart=always
+RestartSec=2
+
+[Install]
+WantedBy=multi-user.target
+
diff --git a/project/lightd/hal/ds18b20.c b/project/lightd/hal/ds18b20.c
new file mode 100644
index 0000000..aa1e01b
--- /dev/null
+++ b/project/lightd/hal/ds18b20.c
@@ -0,0 +1,118 @@
+/*********************************************************************************
+ * Copyright: (C) 2023 LingYun IoT System Studio
+ * All rights reserved.
+ *
+ * Filename: ds18b20.c
+ * Description: This file is temperature sensor DS18B20 code
+ *
+ * Version: 1.0.0(2023/8/10)
+ * Author: Guo Wenxue <guowenxue@gmail.com>
+ * ChangeLog: 1, Release initial version on "2023/8/10 12:13:26"
+ *
+ * Pin connection:
+ *
+ * DS18B20 Module Raspberry Pi Board
+ * VCC <-----> #Pin1(3.3V)
+ * DQ <-----> #Pin7(BCM GPIO4)
+ * GND <-----> GND
+ *
+ * /boot/config.txt:
+ *
+ * dtoverlay=w1-gpio-pullup,gpiopin=4
+ *
+ ********************************************************************************/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+
+#include "logger.h"
+
+/* File Content:
+ pi@raspberrypi:~/guowenxue $ cat /sys/bus/w1/devices/28-041731f7c0ff/w1_slave
+ 3a 01 4b 46 7f ff 0c 10 a5 : crc=a5 YES
+ 3a 01 4b 46 7f ff 0c 10 a5 t=19625
+ */
+
+int ds18b20_get_temperature(float *temp)
+{
+ char w1_path[50] = "/sys/bus/w1/devices/";
+ char chip[20];
+ char buf[128];
+ DIR *dirp;
+ struct dirent *direntp;
+ int fd =-1;
+ char *ptr;
+ int found = 0;
+
+ if( !temp )
+ {
+ return -1;
+ }
+
+ /*+-------------------------------------------------------------------+
+ *| open dierectory /sys/bus/w1/devices to get chipset Serial Number |
+ *+-------------------------------------------------------------------+*/
+ if((dirp = opendir(w1_path)) == NULL)
+ {
+ log_error("opendir error: %s\n", strerror(errno));
+ return -2;
+ }
+
+ while((direntp = readdir(dirp)) != NULL)
+ {
+ if(strstr(direntp->d_name,"28-"))
+ {
+ /* find and get the chipset SN filename */
+ strcpy(chip,direntp->d_name);
+ found = 1;
+ break;
+ }
+ }
+ closedir(dirp);
+
+ if( !found )
+ {
+ log_error("Can not find ds18b20 in %s\n", w1_path);
+ return -3;
+ }
+
+ /* get DS18B20 sample file full path: /sys/bus/w1/devices/28-xxxx/w1_slave */
+ strncat(w1_path, chip, sizeof(w1_path)-strlen(w1_path));
+ strncat(w1_path, "/w1_slave", sizeof(w1_path)-strlen(w1_path));
+
+ /* open file /sys/bus/w1/devices/28-xxxx/w1_slave to get temperature */
+ if( (fd=open(w1_path, O_RDONLY)) < 0 )
+ {
+ log_error("open %s error: %s\n", w1_path, strerror(errno));
+ return -4;
+ }
+
+ if(read(fd, buf, sizeof(buf)) < 0)
+ {
+ log_error("read %s error: %s\n", w1_path, strerror(errno));
+ return -5;
+ }
+
+ ptr = strstr(buf, "t=");
+ if( !ptr )
+ {
+ log_error("ERROR: Can not get temperature\n");
+ return -6;
+ }
+
+ ptr+=2;
+
+ /* convert string value to float value */
+ *temp = atof(ptr)/1000;
+
+ close(fd);
+
+ return 0;
+}
diff --git a/project/lightd/hal/ds18b20.h b/project/lightd/hal/ds18b20.h
new file mode 100644
index 0000000..e756134
--- /dev/null
+++ b/project/lightd/hal/ds18b20.h
@@ -0,0 +1,31 @@
+/*********************************************************************************
+ * Copyright: (C) 2023 LingYun IoT System Studio
+ * All rights reserved.
+ *
+ * Filename: ds18b20.h
+ * Description: This file is temperature sensor DS18B20 code
+ *
+ * Version: 1.0.0(2023/8/10)
+ * Author: Guo Wenxue <guowenxue@gmail.com>
+ * ChangeLog: 1, Release initial version on "2023/8/10 12:13:26"
+ *
+ * Pin connection:
+ *
+ * DS18B20 Module Raspberry Pi Board
+ * VCC <-----> #Pin1(3.3V)
+ * DQ <-----> #Pin7(BCM GPIO4)
+ * GND <-----> GND
+ *
+ * /boot/config.txt:
+ *
+ * dtoverlay=w1-gpio-pullup,gpiopin=4
+ *
+ ********************************************************************************/
+
+#ifndef _DS18B20_H_
+#define _DS18B20_H_
+
+extern int ds18b20_get_temperature(float *temp);
+
+#endif /* ----- #ifndef _DS18B20_H_ ----- */
+
diff --git a/project/lightd/hal/gpio.c b/project/lightd/hal/gpio.c
index 45e1429..fb89c33 100644
--- a/project/lightd/hal/gpio.c
+++ b/project/lightd/hal/gpio.c
@@ -21,13 +21,6 @@
#include "gpio.h"
#define RPI_GPIONAME "gpiochip0"
-#include <errno.h>
-
-#include "logger.h"
-#include "util_proc.h"
-#include "gpio.h"
-
-#define RPI_GPIONAME "gpiochip0"
static struct gpiod_chip *s_chip;
static gpio_t *s_gpio = NULL;
diff --git a/project/lightd/lightd.c b/project/lightd/lightd.c
index 158a3dd..2b1a00a 100644
--- a/project/lightd/lightd.c
+++ b/project/lightd/lightd.c
@@ -26,13 +26,13 @@
#include "util_proc.h"
#include "config.h"
#include "tsl2561.h"
+#include "ds18b20.h"
#define PROG_VERSION "v1.0.0"
#define DAEMON_PIDFILE "/tmp/.lightd.pid"
-int check_sample_time(time_t *last_time, int interval);
-void *thingsboard_subsciber(void *args);
-void *thingsboard_publisher(void *args);
+int check_timeout(time_t *last_time, int interval);
+void *thingsboard_worker(void *args);
static void program_usage(char *progname)
{
@@ -129,10 +129,10 @@
/*
* +--------------------------------+
- * | MQTT Subscriber Thread |
+ * | ThingsBoard MQTT Thread |
* +--------------------------------+
*/
- if( thread_start(&tid, thingsboard_subsciber, &ctx.mqtt ) < 0 )
+ if( thread_start(&tid, thingsboard_worker, &ctx.mqtt ) < 0 )
{
log_error("Start MQTT subsciber worker thread failure\n");
goto cleanup;
@@ -148,12 +148,22 @@
while( ! g_signal.stop )
{
/* TSL2561 update lux in every 5 minutes */
- if(check_sample_time(&last_time, 300))
+ if(check_timeout(&last_time, 300))
{
+ /* The TSL2561 sensor is not present, do not turn on the light */
+ if( !hwinfo->tsl2561 )
+ {
+ log_error("TSL2561 is not present, do not turn on the light\n");
+ lux = hwinfo->lux_threshold + 100.0;
+ goto nextloop;
+ }
+
+ /* The TSL2561 sensor failed, do not turn on the light */
if( tsl2561_get_lux(&lux) < 0 )
{
- log_error("TSL2561 sample Lux failed\n");
- lux = hwinfo->lux_threshold + 100.0;
+ log_error("TSL2561 sample failed, do not turn on the light\n");
+ lux = hwinfo->lux_threshold + 100.0;
+ goto nextloop;
}
if( lux > hwinfo->lux_threshold )
@@ -162,12 +172,13 @@
log_info("Lux[%.3f] <= Treshold[%.3f], need auto light\n", lux, hwinfo->lux_threshold);
}
+ /* It's bright enough, no lighting is needed */
if( lux > hwinfo->lux_threshold )
{
- sleep(1);
- continue;
+ goto nextloop;
}
+ /* It's not bright enough, lighting is necessary */
rv = infrared_detect();
if( rv != 0 )
{
@@ -182,7 +193,8 @@
turn_light("hallway", OFF);
}
- msleep(100);
+nextloop:
+ sleep(1);
}
cleanup:
@@ -192,20 +204,69 @@
return 0;
}
-int check_sample_time(time_t *last_time, int interval)
+/*
+ * +--------------------------------+
+ * | ThingsBoard MQTT Thread |
+ * +--------------------------------+
+ */
+
+int check_timeout(time_t *last_time, int interval)
{
- int need = 0; /* no need sample now */
+ int timeout = 0;
time_t now;
time(&now);
if( difftime(now, *last_time)>interval )
{
- need = 1; /* need sample now */
+ timeout = 1;
*last_time = now;
}
- return need;
+ return timeout;
+}
+
+/* compatible with MQTT publish callback function */
+void pub_connect_callback(struct mosquitto *mosq, void *userdata, int result)
+{
+ mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata;
+ hwinfo_t *hwinfo = (hwinfo_t *)ctx->userdata;
+ int rv = 0;
+ char msg[128];
+ float temp = 0.0; /* temperature */
+ int retain = 0;
+ static time_t last_time = 0;
+
+ /* publish time is not arrive */
+ if( !check_timeout(&last_time, ctx->interval) )
+ {
+ return ;
+ }
+
+ log_debug("Publish topic '%s'\n", ctx->pubTopic);
+
+ if( hwinfo->ds18b20 )
+ {
+ memset(msg, 0, sizeof(msg));
+
+ log_debug("DS18B20 temperature sensor enabled, start broadcast it\n");
+
+ if( ds18b20_get_temperature(&temp)<0 )
+ return ;
+
+ snprintf(msg, sizeof(msg), "{\"temperature\":%.2f}", temp);
+ rv = mosquitto_publish(mosq, NULL, ctx->pubTopic, strlen(msg), msg, ctx->pubQos, retain);
+ if( rv )
+ {
+ log_error("Publisher broadcast message '%s' failure: %d\n", msg, rv);
+ }
+ else
+ {
+ log_info("Publisher broadcast message '%s' ok\n", msg);
+ }
+ }
+
+ return ;
}
void sub_connect_callback(struct mosquitto *mosq, void *userdata, int result)
@@ -214,11 +275,11 @@
if( result )
{
- log_error("Subscriber connect to broker server failed, rv=%d\n", result);
+ log_error("mosquitto connect to broker server failed, rv=%d\n", result);
return ;
}
- log_info("Subscriber connect to broker server[%s:%d] successfully\n", ctx->host, ctx->port);
+ log_info("mosquitto connect to broker server[%s:%d] successfully\n", ctx->host, ctx->port);
mosquitto_subscribe(mosq, NULL, ctx->subTopic, ctx->subQos);
}
@@ -226,7 +287,7 @@
{
mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata;
- log_warn("Subscriber disconnect to broker server[%s:%d], reason=%d\n", ctx->host, ctx->port, result);
+ log_warn("mosquitto disconnect to broker server[%s:%d], reason=%d\n", ctx->host, ctx->port, result);
}
void proc_json_items(cJSON *root, mqtt_ctx_t *ctx)
@@ -282,8 +343,6 @@
}
status = cJSON_IsTrue(item_status) ? ON : OFF;
- log_info("parser JSON message to control '%s' status '%d'\n", device, status);
-
/* 映射 Light 名称并调用控制函数 */
if ( strstr(device, "Indoor") || strstr(device, "indoor"))
{
@@ -326,11 +385,12 @@
return ;
}
-void *thingsboard_subsciber(void *args)
+void *thingsboard_worker(void *args)
{
mqtt_ctx_t *ctx = (mqtt_ctx_t *)args;
struct mosquitto *mosq;
bool session = true;
+ int rv = 0;
mosq = mosquitto_new(ctx->devid, session, ctx);
if( !mosq )
@@ -342,7 +402,7 @@
/* connnect to broker by token or uid/pwd */
if( strlen(ctx->token ) > 0)
{
- log_info("Using token authentication\n");
+ log_info("Using token authentication: '%s'\n", ctx->token);
mosquitto_username_pw_set(mosq, ctx->token, NULL);
}
else if( strlen(ctx->uid)> 0 && strlen(ctx->pwd)> 0 )
@@ -361,16 +421,27 @@
/* connect to MQTT broker */
if( mosquitto_connect(mosq, ctx->host, ctx->port, ctx->keepalive) )
{
- log_error("Subscriber connect to broker[%s:%d] failure: %s\n", ctx->host, ctx->port, strerror(errno));
- msleep(1000);
+ log_error("mosquitto connect to broker[%s:%d] failure: %s\n", ctx->host, ctx->port, strerror(errno));
+ sleep(1);
continue;
}
- /* -1: use default timeout 1000ms 1: unused */
- mosquitto_loop_forever(mosq, -1, 1);
+ while(!g_signal.stop)
+ {
+ pub_connect_callback(mosq, ctx, MOSQ_ERR_SUCCESS);
+
+ /* MQTT process in nonblock mode, timeout for 1s */
+ if( MOSQ_ERR_SUCCESS != (rv = mosquitto_loop(mosq, 1000, 1)) )
+ {
+ log_warn("MQTT loop error: %s, reconnecting...\n", mosquitto_strerror(rv));
+ break;
+ }
+ }
+
+ mosquitto_disconnect(mosq);
+ sleep(1);
}
mosquitto_destroy(mosq);
return NULL;
}
-
--
Gitblit v1.9.1