48 files deleted
13 files modified
5 files added
36 files renamed
| | |
| | | install/ |
| | | |
| | | # ignore files |
| | | *.so* |
| | | *.tar* |
| | | *.o |
| | | *.a |
| | | lib*.so* |
| | | lib*.a |
| | | mqttd |
| | | |
| | | # ctags files |
| | | cscope.* |
| | | tags |
| | | *.tar* |
| | | |
| | | # running files |
| | | *.log |
| | | *.db |
| | | |
| | | # openlibs |
| | | cJSON-* |
| | | mosquitto-* |
| | | libgpiod-* |
| | | openssl-* |
| | | sqlite-* |
| | | libevent-* |
| | | |
| | | # symbolic link |
| | | project/*/booster |
| | | project/*/modules |
| | | project/*/openlibs |
| | | |
| | | # binary file |
| | | project/gpsd/gpsd |
| | | project/thingsboard/thingsboard |
| | |
| | | { |
| | | if ( !(fp = fopen(fname, "a+")) ) |
| | | { |
| | | fprintf(stderr, "%s() failed: %s\n", __func__, strerror(errno)); |
| | | fprintf(stderr, "%s() %s failed: %s\n", __func__, fname, strerror(errno)); |
| | | return -2; |
| | | } |
| | | L.fp = fp; |
| | |
| | | # |
| | | #******************************************************************************* |
| | | |
| | | PWD=$(shell pwd ) |
| | | PWD=$(shell pwd) |
| | | |
| | | BUILD_ARCH=$(shell uname -m) |
| | | ifneq ($(findstring $(BUILD_ARCH), "x86_64" "i386"),) |
| | |
| | | |
| | | LIBNAME=$(shell basename ${PWD} ) |
| | | TOPDIR=$(shell dirname ${PWD} ) |
| | | CFLAGS+=-D_GNU_SOURCE |
| | | |
| | | all: clean |
| | | @rm -f *.o |
| New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2012 Guo Wenxue <guowenxue@gmail.com> |
| | | * All rights reserved. |
| | | * |
| | | * Filename: comport.c |
| | | * Description: This file used to do ioctl() on common device or communicate |
| | | * with serial port/TTY device. |
| | | * |
| | | * Version: 1.0.0(10/18/2011~) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "10/18/2011 10:08:05 AM" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <getopt.h> |
| | | #include <libgen.h> |
| | | #include <sys/ioctl.h> |
| | | |
| | | #include "comport.h" |
| | | |
| | | unsigned char g_ucProcToken = 0x01; |
| | | unsigned char g_ucCtrlZ; |
| | | |
| | | void print_version(char *name); |
| | | void usage(char *name); |
| | | int do_ioctl(char *dev_name, int cmd, int arg); |
| | | void signal_handler(int i_sig); |
| | | void nonblock(void); |
| | | int kbhit(void); |
| | | |
| | | int main(int argc, char **argv) |
| | | { |
| | | int opt = 0; |
| | | int retval = 0; |
| | | int recv_size = 0; |
| | | int i; |
| | | char *dev_name = NULL; |
| | | int baudrate = 115200; |
| | | char *settings = "8N1N"; |
| | | char buf[512]; |
| | | unsigned char disp_mode = 0x00; |
| | | comport_t comport; |
| | | |
| | | struct sigaction sigact; |
| | | |
| | | struct option long_options[] = { |
| | | {"device", required_argument, NULL, 'd'}, |
| | | {"baudrate", required_argument, NULL, 'b'}, |
| | | {"settings", required_argument, NULL, 's'}, |
| | | {"ioctl", required_argument, NULL, 'i'}, |
| | | {"hex", no_argument, NULL, 'x'}, |
| | | {"version", no_argument, NULL, 'v'}, |
| | | {"help", no_argument, NULL, 'h'}, |
| | | {NULL, 0, NULL, 0} |
| | | }; |
| | | |
| | | while ((opt = getopt_long(argc, argv, "d:b:s:ivh", long_options, NULL)) != -1) |
| | | { |
| | | switch (opt) |
| | | { |
| | | case 'd': |
| | | dev_name = optarg; |
| | | break; |
| | | case 'b': |
| | | baudrate = atoi(optarg); |
| | | break; |
| | | case 's': /* Default settings as 8N1N */ |
| | | settings = optarg; |
| | | break; |
| | | case 'i': |
| | | if (5 != argc) |
| | | { |
| | | usage(argv[0]); |
| | | } |
| | | else |
| | | { |
| | | do_ioctl(argv[2], atoi(argv[3]), atoi(argv[4])); |
| | | } |
| | | return 0; |
| | | case 'x': /* Display receive data as Hex mode */ |
| | | disp_mode = 0x01; |
| | | break; |
| | | case 'v': /* version */ |
| | | print_version(argv[0]); |
| | | return 0; |
| | | case 'h': /* help */ |
| | | usage(argv[0]); |
| | | return 0; |
| | | default: |
| | | break; |
| | | } /* end of "switch(opt)" */ |
| | | } |
| | | |
| | | if (argc < 2) |
| | | { |
| | | usage(argv[0]); |
| | | return 0; |
| | | } |
| | | |
| | | if( comport_open(&comport, dev_name, baudrate, settings) < 0 ) |
| | | { |
| | | printf("Failed to open %s with baudrate %d, %s. RetCode [%d]\n", dev_name, baudrate, |
| | | settings, retval); |
| | | return -1; |
| | | } |
| | | |
| | | nonblock(); |
| | | |
| | | /* Process level signal handler */ |
| | | sigemptyset(&sigact.sa_mask); |
| | | sigact.sa_flags = 0; |
| | | sigact.sa_handler = signal_handler; |
| | | |
| | | sigaction(SIGTERM, &sigact, NULL); /* catch terminate signal */ |
| | | sigaction(SIGINT, &sigact, NULL); /* catch interrupt signal */ |
| | | sigaction(SIGSEGV, &sigact, NULL); /* catch segmentation faults */ |
| | | sigaction(SIGTSTP, &sigact, NULL); /* catch ctrl+Z */ |
| | | sigaction(SIGSTOP, &sigact, NULL); /* catch ctrl+Z */ |
| | | |
| | | while (0x01 == g_ucProcToken) |
| | | { |
| | | recv_size = comport_recv(&comport, buf, sizeof(buf) - 1, 10); |
| | | if (recv_size > 0) |
| | | { |
| | | for (i = 0; i < recv_size; i++) |
| | | { |
| | | if (0 == disp_mode) |
| | | printf("%c", buf[i]); |
| | | else |
| | | printf("%02X ", buf[i]); |
| | | } |
| | | fflush(stdout); |
| | | } |
| | | if (0 != kbhit()) |
| | | { |
| | | retval = fgetc(stdin); |
| | | |
| | | if (0x0A == retval) |
| | | { |
| | | buf[0] = 0x0D; /* 13 == 0x0D */ |
| | | } |
| | | else |
| | | { |
| | | buf[0] = retval; |
| | | } |
| | | |
| | | comport_send(&comport, buf, 1); |
| | | } |
| | | else if (0x00 != g_ucCtrlZ) |
| | | { |
| | | g_ucCtrlZ = 0x00; |
| | | buf[0] = 0x1A; |
| | | comport_send(&comport, buf, 1); |
| | | } |
| | | } |
| | | |
| | | comport_close(&comport); |
| | | return 0; |
| | | } |
| | | |
| | | void print_version(char *name) |
| | | { |
| | | char *progname = NULL; |
| | | char *ptr = NULL; |
| | | |
| | | ptr = strdup(name); |
| | | progname = basename(ptr); |
| | | |
| | | printf("%s version: 1.0.0 on %s\n", progname, __DATE__); |
| | | printf("Copyright (C) 2010 guowenxue <guowenxue@gmail.com>\n"); |
| | | |
| | | free(ptr); |
| | | return; |
| | | } |
| | | |
| | | void usage(char *name) |
| | | { |
| | | char *progname = NULL; |
| | | char *ptr = NULL; |
| | | |
| | | ptr = strdup(name); |
| | | progname = basename(ptr); |
| | | printf("Usage1: comport -d <device> [-b <baudrate>][-s <settings>] [-x]\n"); |
| | | printf("Usage2: comport [-i <driver port> <cmd> <arg>][--help][--version]\n"); |
| | | printf(" -d[device ] device name\n"); |
| | | printf(" -b[baudrate] device baudrate (115200, 57600, 19200, 9600), default is 115200\n"); |
| | | printf(" -s[settings] device settings as like 8N1N(default setting)\n"); |
| | | printf(" - data bits: 8, 7\n"); |
| | | printf(" - parity: N=None, O=Odd, E=Even, S=Space\n"); |
| | | printf(" - stop bits: 1, 0\n"); |
| | | printf(" - flow control: N=None, H=Hardware, S=Software, B=Both\n"); |
| | | printf(" -x[hex ] display received data in hex format\n"); |
| | | printf(" -i[ioctl ] ioctl system call (cmd & arg only support int)\n"); |
| | | printf(" -v[version ] Display the program version\n"); |
| | | printf(" -h[help ] Display this help information\n"); |
| | | |
| | | print_version(progname); |
| | | |
| | | free(ptr); |
| | | |
| | | return; |
| | | } |
| | | |
| | | int do_ioctl(char *dev_name, int cmd, int arg) |
| | | { |
| | | int fd = -1; |
| | | int retval = -1; |
| | | if (((fd = open(dev_name, O_RDWR)) < 0)) |
| | | { |
| | | printf("Open device \"%s\" failure: %s\n", dev_name, strerror(errno)); |
| | | return -1; |
| | | } |
| | | |
| | | retval = ioctl(fd, cmd, arg); |
| | | printf("ioctl (%s, %d, %d) returned %d\n", dev_name, cmd, arg, retval); |
| | | |
| | | close(fd); |
| | | return retval; |
| | | } |
| | | |
| | | void signal_handler(int i_sig) |
| | | { |
| | | if (SIGTERM == i_sig || SIGINT == i_sig) |
| | | { |
| | | g_ucProcToken = 0x00; |
| | | } |
| | | else if (20 == i_sig) |
| | | { |
| | | g_ucCtrlZ = 0x01; |
| | | } |
| | | } |
| | | |
| | | void nonblock(void) |
| | | { |
| | | struct termios ttystate; |
| | | |
| | | //get the terminal state |
| | | tcgetattr(STDIN_FILENO, &ttystate); |
| | | |
| | | //turn off canonical mode |
| | | ttystate.c_lflag &= ~ICANON; |
| | | |
| | | //minimum of number input read. |
| | | ttystate.c_cc[VMIN] = 1; |
| | | |
| | | //set the terminal attributes. |
| | | tcsetattr(STDIN_FILENO, TCSANOW, &ttystate); |
| | | } |
| | | |
| | | |
| | | int kbhit(void) |
| | | { |
| | | struct timeval tv; |
| | | |
| | | fd_set fds; |
| | | tv.tv_sec = 0; |
| | | tv.tv_usec = 0; |
| | | FD_ZERO(&fds); |
| | | FD_SET(STDIN_FILENO, &fds); //STDIN_FILENO is 0 |
| | | |
| | | select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv); |
| | | |
| | | return FD_ISSET(STDIN_FILENO, &fds); |
| | | } |
| | |
| | | PWD=$(shell pwd) |
| | | LIB_PATH=$(shell dirname ${PWD}) |
| | | LIB_NAME=$(shell basename ${LIB_PATH}) |
| | | INSTPATH=/tftp |
| | | |
| | | #ARCH ?= i386 |
| | | #ARCH?=arm926t |
| | | ARCH?=arm920t |
| | | |
| | | #LINK_MODE=STATIC |
| | | MODE=PRODUCTION |
| | | DEBUG=1 |
| | | |
| | | INSTPATH=/tftp |
| | | |
| | | #CROSS_COMPILE=aarch64-linux-gnu- |
| | | BUILD_ARCH=$(shell uname -m) |
| | | ifneq ($(findstring $(BUILD_ARCH), "x86_64" "i386"),) |
| | | CROSS_COMPILE?=arm-linux-gnueabihf- |
| | | endif |
| | | |
| | | export CC=${CROSS_COMPILE}gcc |
| | | export CXX=${CROSS_COMPILE}g++ |
| | |
| | | |
| | | if( check_daemon_running(pidfile) ) |
| | | { |
| | | log_error("Program already running, process exit now"); |
| | | log_error("Program already running, process exit now\n"); |
| | | return -1; |
| | | } |
| | | |
| | |
| | | * *****************************************************************************/ |
| | | int set_daemon_running(const char *pid_file) |
| | | { |
| | | daemonize(0, 1); |
| | | daemon(0, 1); |
| | | log_info("Program running as daemon [PID:%d].\n", getpid()); |
| | | |
| | | if (record_daemon_pid(pid_file) < 0) |
| | |
| | | return -2; |
| | | } |
| | | |
| | | for(i=0; i<ctx->count; i++) |
| | | { |
| | | if( which == i ) |
| | | { |
| | | led = &ctx->leds[i]; |
| | | for(i=0; i<ctx->count; i++) |
| | | { |
| | | if( which == i ) |
| | | { |
| | | led = &ctx->leds[i]; |
| | | |
| | | led->line = gpiod_chip_get_line(ctx->chip, led->gpio); |
| | | if( !led->line ) |
| | | { |
| | | log_error("open gpioline for %s[%d] failed\n", led->name, led->gpio); |
| | | rv = -3; |
| | | goto failed; |
| | | } |
| | | led->line = gpiod_chip_get_line(ctx->chip, led->gpio); |
| | | if( !led->line ) |
| | | { |
| | | log_error("open gpioline for %s[%d] failed\n", led->name, led->gpio); |
| | | rv = -3; |
| | | goto failed; |
| | | } |
| | | |
| | | rv = gpiod_line_request_output(led->line, led->name, !led->active); |
| | | if( rv ) |
| | | { |
| | | log_error("request gpio output for %5s[%d] failed: %s\n", led->name, led->gpio, strerror(errno)); |
| | | rv = -4; |
| | | goto failed; |
| | | } |
| | | rv = gpiod_line_request_output(led->line, led->name, !led->active); |
| | | if( rv ) |
| | | { |
| | | log_error("request gpio output for %5s[%d] failed: %s\n", led->name, led->gpio, strerror(errno)); |
| | | rv = -4; |
| | | goto failed; |
| | | } |
| | | |
| | | log_debug("request %5s led[%d] for gpio output okay\n", led->name, led->gpio); |
| | | } |
| | | } |
| | | log_debug("request %5s led[%d] for gpio output okay\n", led->name, led->gpio); |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | |
| | |
| | | int i; |
| | | led_info_t *led; |
| | | |
| | | log_warn("terminate RGB Led gpios\n"); |
| | | log_debug("terminate RGB Led gpios\n"); |
| | | |
| | | if( !ctx ) |
| | | { |
| | |
| | | return 0; |
| | | |
| | | for(i=0; i<ctx->count; i++) |
| | | { |
| | | if( which == i ) |
| | | { |
| | | led = &ctx->leds[i]; |
| | | { |
| | | if( which == i ) |
| | | { |
| | | led = &ctx->leds[i]; |
| | | |
| | | if( led->line ) |
| | | gpiod_line_release(led->line); |
| | | } |
| | | } |
| | | if( led->line ) |
| | | gpiod_line_release(led->line); |
| | | } |
| | | } |
| | | |
| | | gpiod_chip_close(ctx->chip); |
| | | return 0; |
| | |
| | | |
| | | led = &ctx.leds[which]; |
| | | |
| | | log_info("turn Led %s %s\n", led->name, cmd?"on":"off"); |
| | | |
| | | if( OFF == cmd ) |
| | | { |
| | | gpiod_line_set_value(led->line, !led->active); |
| | |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | i2c_read(fd, SHT20_I2CADDR, buf, 3); |
| | | log_dump(LOG_LEVEL_DEBUG, "Temperature sample data: ", buf, 3); |
| | | log_dump(LOG_LEVEL_TRACE, "Temperature sample data: ", buf, 3); |
| | | |
| | | if( !sht20_checksum(buf, 2, buf[2]) ) |
| | | { |
| | |
| | | |
| | | memset(buf, 0, sizeof(buf)); |
| | | i2c_read(fd, SHT20_I2CADDR, buf, 3); |
| | | log_dump(LOG_LEVEL_DEBUG, "Relative humidity sample data: ", buf, 3); |
| | | log_dump(LOG_LEVEL_TRACE, "Relative humidity sample data: ", buf, 3); |
| | | |
| | | if( !sht20_checksum(buf, 2, buf[2]) ) |
| | | { |
| | |
| | | PACK_SUFIX=tar.gz |
| | | |
| | | # LingYun source code FTP server |
| | | LY_FTP=http://main.weike-iot.com:2211/src/ |
| | | LY_FTP=http://weike-iot.com:2211/src/ |
| | | |
| | | # library download URL address |
| | | LIB_URL=$LY_FTP |
| | |
| | | PACK_SUFIX=tar.gz |
| | | |
| | | # LingYun source code FTP server |
| | | LY_FTP=http://main.weike-iot.com:2211/src/ |
| | | LY_FTP=http://weike-iot.com:2211/src/ |
| | | |
| | | # library download URL address |
| | | LIB_URL=$LY_FTP |
| | |
| | | PACK_SUFIX=tar.gz |
| | | |
| | | # LingYun source code FTP server |
| | | LY_FTP=http://main.weike-iot.com:2211/src/ |
| | | LY_FTP=http://weike-iot.com:2211/src/ |
| | | |
| | | # library download URL address |
| | | LIB_URL=$LY_FTP |
| | |
| | | |
| | | PRJ_PATH=$(shell pwd) |
| | | libs=libgpiod cjson openssl mosquitto libevent |
| | | |
| | | openssl_dir := $(shell ls -d openssl/ 2>/dev/null | sed 's|/||g') |
| | | other_dirs := $(shell ls -d */ 2>/dev/null | grep -v '^install/' | grep -v '^openssl/' | sed 's|/||g') |
| | | libs := $(openssl_dir) $(other_dirs) |
| | | |
| | | # clear CFLAGS |
| | | CLFAGS= |
| | | |
| | | all: |
| | | for dir in ${libs} ; do cd ${PRJ_PATH}/$${dir} && ./build.sh ; done |
| | |
| | | PACK_SUFIX=tar.gz |
| | | |
| | | # LingYun source code FTP server |
| | | LY_FTP=http://main.weike-iot.com:2211/src/ |
| | | LY_FTP=http://weike-iot.com:2211/src/ |
| | | |
| | | # library download URL address |
| | | LIB_URL=$LY_FTP |
| | |
| | | PACK_SUFIX=tar.gz |
| | | |
| | | # LingYun source code FTP server |
| | | LY_FTP=http://main.weike-iot.com:2211/src/ |
| | | LY_FTP=http://weike-iot.com:2211/src/ |
| | | |
| | | # library download URL address |
| | | LIB_URL=$LY_FTP |
| File was renamed from project/coreMQTT/conf.c |
| | |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: conf.c |
| | | * Filename: config.c |
| | | * Description: This file is mqttd configure file parser function |
| | | * |
| | | * |
| | | * Version: 1.0.0(2019年06月25日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年06月25日 22时23分55秒" |
| | | * |
| | | * |
| | | ********************************************************************************/ |
| | | #include "conf.h" |
| | | #include "config.h" |
| | | #include "logger.h" |
| | | #include "iniparser.h" |
| | | |
| | | |
| | | int mqttd_parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug) |
| | | int parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug) |
| | | { |
| | | dictionary *ini; |
| | | const char *str; |
| | | int val; |
| | | int rv = 0; |
| | | int val; |
| | | int rv = 0; |
| | | |
| | | if( !conf_file || !ctx ) |
| | | { |
| | | { |
| | | fprintf(stderr, "%s() Invalid input arguments\n", __func__); |
| | | return -1; |
| | | } |
| | |
| | | /*+------------------------------------------------------+ |
| | | *| parser logger settings and start logger system | |
| | | *+------------------------------------------------------+*/ |
| | | if( !debug ) |
| | | if( !debug ) |
| | | { |
| | | str = iniparser_getstring(ini, "logger:file", "/tmp/mqttd.log"); |
| | | str = iniparser_getstring(ini, "logger:file", "/tmp/thingsboard.log"); |
| | | strncpy(ctx->logfile, str, sizeof(ctx->logfile)); |
| | | ctx->logsize = iniparser_getint(ini, "logger:size", 1024); |
| | | ctx->loglevel = iniparser_getint(ini, "logger:level", LOG_LEVEL_INFO); |
| | |
| | | ctx->logsize = 0; |
| | | } |
| | | |
| | | if( log_open(ctx->logfile, ctx->loglevel, ctx->logsize, LOG_LOCK_DISABLE) < 0 ) |
| | | if( log_open(ctx->logfile, ctx->loglevel, ctx->logsize, LOG_LOCK_DISABLE) < 0 ) |
| | | { |
| | | fprintf(stderr, "Logger system initialise failure\n"); |
| | | return -2; |
| | |
| | | } |
| | | strncpy(ctx->host, str, sizeof(ctx->host) ); |
| | | |
| | | if( (val=iniparser_getint(ini, "broker:port", -1)) < 0 ) |
| | | if( (val=iniparser_getint(ini, "broker:port", -1)) < 0 ) |
| | | { |
| | | log_error("ERROR: Parser MQTT broker server port failure\n"); |
| | | rv = -5; |
| | |
| | | ctx->port = val; |
| | | log_info("Parser MQTT broker server [%s:%d]\n", ctx->host, ctx->port); |
| | | |
| | | str=iniparser_getstring(ini, "broker:token", NULL); |
| | | strncpy(ctx->token, str, sizeof(ctx->uid) ); |
| | | |
| | | str=iniparser_getstring(ini, "broker:username", NULL); |
| | | strncpy(ctx->uid, str, sizeof(ctx->uid) ); |
| | | |
| File was renamed from project/coreMQTT/conf.h |
| | |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: conf.h |
| | | * Filename: config.h |
| | | * Description: This file is mqttd configure file parser function |
| | | * |
| | | * |
| | | * Version: 1.0.0(2019年06月25日) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "2019年06月25日 22时23分55秒" |
| | | * |
| | | * |
| | | ********************************************************************************/ |
| | | #ifndef __CONF_H_ |
| | | #define __CONF_H_ |
| | |
| | | #define DEF_PUBINTERVAL 120 |
| | | #define DEF_QOS Qos2 |
| | | |
| | | typedef struct hwconf_s |
| | | typedef struct hwconf_s |
| | | { |
| | | int relay; /* relay aviable or not. 0:Disable 1: Enable */ |
| | | int led; /* RGB led aviable or not. 0:Disable 1: Enable */ |
| | |
| | | int ds18b20; /* DS1B820 aviable or not. 0:Disable 1: Enable */ |
| | | int sht2x; /* SHT20 aviable or not. 0:Disable 1: Enable */ |
| | | int tsl2561; /* TSL2561 aviable or not. 0:Disable 1: Enable */ |
| | | } hwconf_t; |
| | | } hwconf_t; |
| | | |
| | | |
| | | typedef struct mqtt_ctx_s |
| | |
| | | int port; /* MQTT broker listen port */ |
| | | char uid[64]; /* username */ |
| | | char pwd[64]; /* password */ |
| | | char token[64]; /* token */ |
| | | int keepalive; /* MQTT broker send PING message to subsciber/publisher keepalive timeout<seconds> */ |
| | | |
| | | /* Publisher settings */ |
| | |
| | | } mqtt_ctx_t; |
| | | |
| | | |
| | | extern int mqttd_parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug); |
| | | extern int parser_conf(const char *conf_file, mqtt_ctx_t *ctx, int debug); |
| | | |
| | | #endif /* ----- #ifndef _CONF_H_ ----- */ |
| | | |
| New file |
| | |
| | | [common] |
| | | devid="raspberrypi4b" |
| | | |
| | | # 树莓派连接的外设信息,0:禁用或未连接 其他: 使能或相关硬件连接的Pin管脚(wPI模式) |
| | | [hardware] |
| | | |
| | | # 是否使能 RGB 三色灯模块,0:禁用 1:使能 |
| | | rgbled=1 |
| | | |
| | | # 是否使能 SHT2X 温湿度传感器模块,0:禁用 1:使能 |
| | | sht2x=1 |
| | | |
| | | [logger] |
| | | |
| | | # 日志记录文件 |
| | | file=/var/log/thingsboard.log |
| | | |
| | | # 日志级别: 0:ERROR 1:WARN 2:INFO 3:DEBUG 4:TRACE |
| | | level=2 |
| | | |
| | | # 日志回滚大小 |
| | | size=1024 |
| | | |
| | | |
| | | [broker] |
| | | |
| | | # broker 服务器地址和端口号 |
| | | hostname="weike-iot.com" |
| | | port=2262 |
| | | |
| | | # broker 认证连接的 token |
| | | token="l3ie6juxf0t9wn8kjsk4" |
| | | |
| | | # broker 认证连接的用户名和密码 |
| | | username="lingyun" |
| | | password="lingyun" |
| | | |
| | | |
| | | |
| | | # broker给subsciber和publisher发送PING报文保持 keepalive 的时间周期,单位是秒 |
| | | keepalive=30 |
| | | |
| | | # Qos0: 发送者只发送一次消息,不进行重试,Broker不会返回确认消息。在Qos0情况下,Broker可能没有接受到消息 |
| | | # Qos1: 发送者最少发送一次消息,确保消息到达Broker,Broker需要返回确认消息PUBACK。在Qos1情况下,Broker可能接受到重复消息 |
| | | # Qos2: Qos2使用两阶段确认来保证消息的不丢失和不重复。在Qos2情况下,Broker肯定会收到消息,且只收到一次 |
| | | |
| | | [publisher] |
| | | |
| | | # mosquitto_pub -h weike-iot.com -p 2262 -t v1/devices/me/telemetry -i "raspberrypi4b" -u "l3ie6juxf0t9wn8kjsk4" -m '{"temperature":28.55, "humidity":70.65}' |
| | | pubTopic="v1/devices/me/telemetry" |
| | | pubQos=0 |
| | | |
| | | # Publisher上报传感器数据的周期,单位是秒 |
| | | interval=60 |
| | | |
| | | [subsciber] |
| | | |
| | | # mosquitto_sub -h weike-iot.com -p 2262 -u "l3ie6juxf0t9wn8kjsk4" -t "v1/devices/me/rpc/request/+" |
| | | # {"method":"setValue","params":{"device":"RedLed","status":true}} |
| | | subTopic="v1/devices/me/rpc/request/+" |
| | | subQos=0 |
| | | |
| New file |
| | |
| | | [Unit] |
| | | Description=RaspberryPi ThingsBoard Client Service |
| | | After=network.target |
| | | |
| | | [Service] |
| | | Type=simple |
| | | ExecStartPre=/bin/rm -f /tmp/.thingsboard.pid /var/log/thingsboard.log |
| | | ExecStart=/usr/bin/thingsboard -c /etc/thingsboard.conf |
| | | |
| | | Restart=always |
| | | RestartSec=2 |
| | | |
| | | [Install] |
| | | WantedBy=multi-user.target |
| | | |
| File was renamed from project/mosquitto/makefile |
| | |
| | | #******************************************************************************* |
| | | |
| | | PRJ_PATH=$(shell pwd) |
| | | APP_NAME = mqttd |
| | | APP_NAME = thingsboard |
| | | |
| | | BUILD_ARCH=$(shell uname -m) |
| | | ifneq ($(findstring $(BUILD_ARCH), "x86_64" "i386"),) |
| New file |
| | |
| | | /********************************************************************************* |
| | | * Copyright: (C) 2019 LingYun IoT System Studio |
| | | * All rights reserved. |
| | | * |
| | | * Filename: main.c |
| | | * Description: This file |
| | | * |
| | | * Version: 1.0.0(29/01/19) |
| | | * Author: Guo Wenxue <guowenxue@gmail.com> |
| | | * ChangeLog: 1, Release initial version on "29/01/19 15:34:41" |
| | | * |
| | | ********************************************************************************/ |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <time.h> |
| | | #include <getopt.h> |
| | | #include <libgen.h> |
| | | #include <string.h> |
| | | #include <errno.h> |
| | | |
| | | #include <mosquitto.h> |
| | | #include <cjson/cJSON.h> |
| | | |
| | | #include "logger.h" |
| | | #include "util_proc.h" |
| | | #include "config.h" |
| | | #include "sht20.h" |
| | | #include "leds.h" |
| | | |
| | | #define PROG_VERSION "v1.0.0" |
| | | #define DAEMON_PIDFILE "/tmp/.thingsboard.pid" |
| | | |
| | | void *mqtt_sub_worker(void *args); |
| | | void *mqtt_pub_worker(void *args); |
| | | |
| | | static void program_usage(char *progname) |
| | | { |
| | | |
| | | printf("Usage: %s [OPTION]...\n", progname); |
| | | printf(" %s is LingYun studio MQTT daemon program running on RaspberryPi\n", progname); |
| | | |
| | | printf("\nMandatory arguments to long options are mandatory for short options too:\n"); |
| | | printf(" -b[daemon ] Running in daemon mode\n"); |
| | | printf(" -d[debug ] Running in debug mode\n"); |
| | | printf(" -c[conf ] Specify configure file\n"); |
| | | printf(" -h[help ] Display this help information\n"); |
| | | printf(" -v[version ] Display the program version\n"); |
| | | |
| | | printf("\n%s version %s\n", progname, PROG_VERSION); |
| | | return; |
| | | } |
| | | |
| | | int main (int argc, char **argv) |
| | | { |
| | | int daemon = 0; |
| | | pthread_t tid; |
| | | mqtt_ctx_t ctx; |
| | | char *conf_file="/etc/thingsboard.conf"; |
| | | int debug = 0; |
| | | int opt; |
| | | char *progname=NULL; |
| | | |
| | | struct option long_options[] = { |
| | | {"conf", required_argument, NULL, 'c'}, |
| | | {"daemon", no_argument, NULL, 'b'}, |
| | | {"debug", no_argument, NULL, 'd'}, |
| | | {"version", no_argument, NULL, 'v'}, |
| | | {"help", no_argument, NULL, 'h'}, |
| | | {NULL, 0, NULL, 0} |
| | | }; |
| | | |
| | | progname = (char *)basename(argv[0]); |
| | | |
| | | /* parser the command line parameters */ |
| | | while ((opt = getopt_long(argc, argv, "c:bdvh", long_options, NULL)) != -1) |
| | | { |
| | | switch (opt) |
| | | { |
| | | case 'c': /* Set configure file */ |
| | | conf_file = optarg; |
| | | break; |
| | | |
| | | case 'b': /* Set daemon running */ |
| | | daemon = 1; |
| | | break; |
| | | |
| | | case 'd': /* Set debug running */ |
| | | debug = 1; |
| | | break; |
| | | |
| | | case 'v': /* Get software version */ |
| | | printf("%s version %s\n", progname, PROG_VERSION); |
| | | return 0; |
| | | |
| | | case 'h': /* Get help information */ |
| | | program_usage(progname); |
| | | return 0; |
| | | |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | /* parser configure file */ |
| | | if( parser_conf(conf_file, &ctx, debug)<0 ) |
| | | { |
| | | fprintf(stderr, "Parser thingsboard configure file failure\n"); |
| | | return -2; |
| | | } |
| | | |
| | | /* install signal proc handler */ |
| | | install_default_signal(); |
| | | |
| | | /* check program already running or not, if already running then exit, or set running as daemon */ |
| | | if( check_set_program_running(daemon, DAEMON_PIDFILE) < 0 ) |
| | | goto cleanup; |
| | | |
| | | /* initial mosquitto library */ |
| | | mosquitto_lib_init(); |
| | | |
| | | /* create MQTT subsciber thread */ |
| | | if( thread_start(&tid, mqtt_sub_worker, &ctx ) < 0 ) |
| | | { |
| | | log_error("Start MQTT subsciber worker thread failure\n"); |
| | | goto cleanup; |
| | | } |
| | | log_info("Start MQTT subsciber worker thread ok\n"); |
| | | |
| | | /* create MQTT publisher thread */ |
| | | if( thread_start(&tid, mqtt_pub_worker, &ctx) < 0 ) |
| | | { |
| | | log_error("Start MQTT publisher worker thread failure\n"); |
| | | goto cleanup; |
| | | } |
| | | log_info("Start MQTT publisher worker thread ok\n"); |
| | | |
| | | while( ! g_signal.stop ) |
| | | { |
| | | msleep(1000); |
| | | } |
| | | |
| | | cleanup: |
| | | mosquitto_lib_cleanup(); |
| | | log_close(); |
| | | |
| | | return 0; |
| | | } /* ----- End of main() ----- */ |
| | | |
| | | void pub_connect_callback(struct mosquitto *mosq, void *userdata, int result) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata; |
| | | int rv = 0; |
| | | char msg[128]; |
| | | float temp = 0.0; /* temperature */ |
| | | float rh = 0.0; /* relative humidity */ |
| | | int retain = 0; |
| | | |
| | | if( result ) |
| | | { |
| | | log_error("Publisher connect to broker server[%s:%d] failed, rv=%d\n", ctx->host, ctx->port, result); |
| | | return ; |
| | | } |
| | | |
| | | log_info("Publisher connect to broker server[%s:%d] successfully\n", ctx->host, ctx->port); |
| | | log_debug("Publish topic '%s'\n", ctx->pubTopic); |
| | | |
| | | if( ctx->hwconf.sht2x ) |
| | | { |
| | | memset(msg, 0, sizeof(msg)); |
| | | |
| | | log_debug("SHT2X temperature and humidity sensor enabled, start broadcast it\n"); |
| | | |
| | | if( 0 == sht2x_get_temp_humidity(&temp, &rh) ) |
| | | snprintf(msg, sizeof(msg), "{\"temperature\":%.2f, \"humidity\":%.2f}", temp, rh); |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | msleep(500); |
| | | log_info("Publisher broadcast over and disconnect broker now\n", ctx->host, ctx->port); |
| | | mosquitto_disconnect(mosq); |
| | | |
| | | return ; |
| | | } |
| | | |
| | | |
| | | void *mqtt_pub_worker(void *args) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)args; |
| | | struct mosquitto *mosq; |
| | | bool session = true; |
| | | |
| | | mosq = mosquitto_new(ctx->devid, session, ctx); |
| | | if( !mosq ) |
| | | { |
| | | log_error("mosquitto_new failure\n"); |
| | | return NULL; |
| | | } |
| | | |
| | | /* connnect to broker by token or uid/pwd */ |
| | | if( strlen(ctx->token ) > 0) |
| | | { |
| | | log_info("Using token authentication\n"); |
| | | mosquitto_username_pw_set(mosq, ctx->token, NULL); |
| | | } |
| | | else if( strlen(ctx->uid)> 0 && strlen(ctx->pwd)> 0 ) |
| | | { |
| | | log_info("Using username/password authentication\n"); |
| | | mosquitto_username_pw_set(mosq, ctx->uid, ctx->pwd); |
| | | } |
| | | |
| | | /* set callback functions */ |
| | | mosquitto_connect_callback_set(mosq, pub_connect_callback); |
| | | |
| | | while( !g_signal.stop ) |
| | | { |
| | | /* connect to MQTT broker */ |
| | | if( mosquitto_connect(mosq, ctx->host, ctx->port, ctx->keepalive) ) |
| | | { |
| | | log_error("Publisher connect to broker[%s:%d] failure: %s\n", ctx->host, ctx->port, strerror(errno)); |
| | | msleep(1000); |
| | | continue; |
| | | } |
| | | |
| | | /* -1: use default timeout 1000ms 1: unused */ |
| | | mosquitto_loop_forever(mosq, -1, 1); |
| | | |
| | | /* Publisher broadcast sensors data message interval time, unit seconds */ |
| | | sleep( ctx->interval ); |
| | | } |
| | | |
| | | mosquitto_destroy(mosq); |
| | | return NULL; |
| | | } |
| | | |
| | | void sub_connect_callback(struct mosquitto *mosq, void *userdata, int result) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata; |
| | | |
| | | if( result ) |
| | | { |
| | | log_error("Subscriber 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); |
| | | mosquitto_subscribe(mosq, NULL, ctx->subTopic, ctx->subQos); |
| | | } |
| | | |
| | | void sub_disconnect_callback(struct mosquitto *mosq, void *userdata, int result) |
| | | { |
| | | 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); |
| | | } |
| | | |
| | | void proc_json_items(cJSON *root, mqtt_ctx_t *ctx) |
| | | { |
| | | cJSON *item_method; |
| | | cJSON *item_params; |
| | | cJSON *item_device; |
| | | cJSON *item_status; |
| | | |
| | | char *method; |
| | | char *device; |
| | | int status; |
| | | |
| | | /* 获取 method 字段 */ |
| | | item_method = cJSON_GetObjectItem(root, "method"); |
| | | if (item_method == NULL || !cJSON_IsString(item_method)) |
| | | { |
| | | printf("JSON missing method\n"); |
| | | return; |
| | | } |
| | | method = item_method->valuestring; |
| | | |
| | | /* 只处理 setValue 命令 */ |
| | | if (strcmp(method, "setValue") != 0) |
| | | { |
| | | printf("Ignore method: %s\n", method); |
| | | return; |
| | | } |
| | | |
| | | /* 获取 params 对象 */ |
| | | item_params = cJSON_GetObjectItem(root, "params"); |
| | | if (item_params == NULL || !cJSON_IsObject(item_params)) |
| | | { |
| | | printf("JSON missing params\n"); |
| | | return; |
| | | } |
| | | |
| | | /* 获取 params.device */ |
| | | item_device = cJSON_GetObjectItem(item_params, "device"); |
| | | if (item_device == NULL || !cJSON_IsString(item_device)) |
| | | { |
| | | printf("JSON missing params.device\n"); |
| | | return; |
| | | } |
| | | device = item_device->valuestring; |
| | | |
| | | /* 获取 params.status (布尔值) */ |
| | | item_status = cJSON_GetObjectItem(item_params, "status"); |
| | | if (item_status == NULL || !(cJSON_IsBool(item_status))) |
| | | { |
| | | printf("JSON missing params.status\n"); |
| | | return; |
| | | } |
| | | status = cJSON_IsTrue(item_status) ? ON : OFF; |
| | | |
| | | /* 映射 LED 名称并调用控制函数 */ |
| | | if (strcmp(device, "RedLed") == 0) |
| | | { |
| | | turn_led(LED_R, status); |
| | | } |
| | | else if (strcmp(device, "GreenLed") == 0) |
| | | { |
| | | turn_led(LED_G, status); |
| | | } |
| | | else if (strcmp(device, "BlueLed") == 0) |
| | | { |
| | | turn_led(LED_B, status); |
| | | } |
| | | |
| | | return; |
| | | } |
| | | |
| | | void sub_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)userdata; |
| | | |
| | | cJSON *root = NULL; |
| | | |
| | | if ( !message->payloadlen ) |
| | | { |
| | | log_error("%s (null)\n", message->topic); |
| | | return ; |
| | | } |
| | | |
| | | log_info("Subscriber receive message: '%s'\n", message->payload); |
| | | |
| | | root = cJSON_Parse(message->payload); |
| | | if( !root ) |
| | | { |
| | | log_error("cJSON_Parse parser failure: %s\n", cJSON_GetErrorPtr()); |
| | | return ; |
| | | } |
| | | |
| | | proc_json_items(root, ctx); |
| | | |
| | | /* must delete it, or it will result memory leak */ |
| | | cJSON_Delete(root); |
| | | |
| | | return ; |
| | | } |
| | | |
| | | |
| | | void *mqtt_sub_worker(void *args) |
| | | { |
| | | mqtt_ctx_t *ctx = (mqtt_ctx_t *)args; |
| | | struct mosquitto *mosq; |
| | | bool session = true; |
| | | |
| | | mosq = mosquitto_new(ctx->devid, session, ctx); |
| | | if( !mosq ) |
| | | { |
| | | log_error("mosquitto_new failure\n"); |
| | | return NULL; |
| | | } |
| | | |
| | | /* connnect to broker by token or uid/pwd */ |
| | | if( strlen(ctx->token ) > 0) |
| | | { |
| | | log_info("Using token authentication\n"); |
| | | mosquitto_username_pw_set(mosq, ctx->token, NULL); |
| | | } |
| | | else if( strlen(ctx->uid)> 0 && strlen(ctx->pwd)> 0 ) |
| | | { |
| | | log_info("Using username/password authentication\n"); |
| | | mosquitto_username_pw_set(mosq, ctx->uid, ctx->pwd); |
| | | } |
| | | |
| | | /* set callback functions */ |
| | | mosquitto_connect_callback_set(mosq, sub_connect_callback); |
| | | mosquitto_disconnect_callback_set(mosq, sub_disconnect_callback); |
| | | mosquitto_message_callback_set(mosq, sub_message_callback); |
| | | |
| | | while( !g_signal.stop ) |
| | | { |
| | | /* 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); |
| | | continue; |
| | | } |
| | | |
| | | /* -1: use default timeout 1000ms 1: unused */ |
| | | mosquitto_loop_forever(mosq, -1, 1); |
| | | } |
| | | |
| | | mosquitto_destroy(mosq); |
| | | return NULL; |
| | | } |
| | | |
| New file |
| | |
| | | #!/bin/bash |
| | | |
| | | # display in red |
| | | function pr_error() { |
| | | echo "" |
| | | echo -e "\033[40;31m --E-- $1 \033[0m" |
| | | echo "" |
| | | } |
| | | |
| | | # display in yellow |
| | | function pr_warn() { |
| | | echo "" |
| | | echo -e "\033[40;33m --W-- $1 \033[0m" |
| | | echo "" |
| | | } |
| | | |
| | | # display in green |
| | | function pr_info() { |
| | | echo "" |
| | | echo -e "\033[40;32m --I-- $1 \033[0m" |
| | | echo "" |
| | | } |
| | | |
| | | function update_source() |
| | | { |
| | | APT_FILE=/etc/apt/sources.list |
| | | |
| | | pr_warn "start update apt source to ustc" |
| | | |
| | | if [ ! -f $APT_FILE.orig ] ; then |
| | | mv $APT_FILE $APT_FILE.orig |
| | | fi |
| | | |
| | | cat > $APT_FILE <<EOF |
| | | deb http://mirrors.ustc.edu.cn/raspbian/raspbian/ bullseye main contrib non-free rpi |
| | | deb-src http://mirrors.ustc.edu.cn/raspbian/raspbian/ bullseye main contrib non-free rpi |
| | | EOF |
| | | } |
| | | |
| | | function apt_update() |
| | | { |
| | | pr_warn "start update apt updata and upgrade" |
| | | |
| | | apt update |
| | | apt upgrade -y |
| | | apt autoremove -y |
| | | } |
| | | |
| | | function apt_install() |
| | | { |
| | | pr_warn "start apt install system tools" |
| | | |
| | | apt install -y make vim gawk wget curl unzip sed tree coreutils diffstat git subversion \ |
| | | groff lzop make gcc g++ libtool automake autoconf autoconf-archive flex texinfo bison \ |
| | | build-essential libelf-dev lrzsz |
| | | |
| | | # apt-cache policy libssl-dev |
| | | apt install -y libssl-dev=1.1.1n-0+deb11u1 libssl1.1 |
| | | } |
| | | |
| | | if [ `id -u` != 0 ] ; then |
| | | pr_error "This shell script must run as root." |
| | | exit 1; |
| | | fi |
| | | |
| | | update_source |
| | | |
| | | apt_update |
| | | |
| | | apt_install |
| | | |
| | | |