| | |
| | | #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) |
| | | { |
| | |
| | | |
| | | /* |
| | | * +--------------------------------+ |
| | | * | 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; |
| | |
| | | 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 ) |
| | |
| | | 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 ) |
| | | { |
| | |
| | | |
| | | sleep(hwinfo->light_intval); |
| | | |
| | | turn_light("indoor", ON); |
| | | turn_light("hallway", ON); |
| | | turn_light("indoor", OFF); |
| | | turn_light("hallway", OFF); |
| | | } |
| | | |
| | | msleep(100); |
| | | nextloop: |
| | | sleep(1); |
| | | } |
| | | |
| | | cleanup: |
| | |
| | | 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) |
| | |
| | | |
| | | 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); |
| | | } |
| | | |
| | |
| | | { |
| | | 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) |
| | |
| | | } |
| | | 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")) |
| | | { |
| | |
| | | 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 ) |
| | |
| | | /* 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 ) |
| | |
| | | /* 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; |
| | | } |
| | | |