From d8b424f653c5076ac2deace32351e3526c7210cb Mon Sep 17 00:00:00 2001
From: Zip <76966589@qq.com>
Date: Mon, 15 Apr 2019 15:01:32 +0800
Subject: [PATCH] =?UTF-8?q?fix:=E5=A4=9A=E4=B8=AAztc1=E5=8A=A0=E5=85=A5has?=
=?UTF-8?q?s=20=E5=AE=9E=E4=BD=93id=E9=87=8D=E5=A4=8D=E7=9A=84=E9=97=AE?=
=?UTF-8?q?=E9=A2=98=20add:=E5=A2=9E=E5=8A=A0=E5=BD=93=E5=89=8D=E5=90=AF?=
=?UTF-8?q?=E5=8A=A8=E6=97=B6=E9=97=B4(=E4=BB=85app=E8=8E=B7=E5=8F=96,hass?=
=?UTF-8?q?=E6=97=A0=E6=B3=95=E8=8E=B7=E5=8F=96)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
TC1/main.c | 4 +-
TC1/main.h | 4 +-
TC1/user_mqtt_client.c | 241 ++++++++++++------
TC1/user_mqtt_client.h | 8 +
TC1/user_rtc.c | 12 +-
.../binary/TC1@MK3031@moc.all.bin | Bin 1959768 -> 1959768 bytes
.../binary/TC1@MK3031@moc.ota.bin | Bin 532776 -> 533528 bytes
7 files changed, 180 insertions(+), 89 deletions(-)
diff --git a/TC1/main.c b/TC1/main.c
index 0ce1e8c..f55d5a5 100644
--- a/TC1/main.c
+++ b/TC1/main.c
@@ -10,8 +10,10 @@
#define os_log(format, ...) custom_log("TC1", format, ##__VA_ARGS__)
-char rtc_init = 0; //sntp校时成功标志位
+
+char rtc_init = 0; //sntp校时成功标志位
+uint32_t total_time=0;
char strMac[16] = { 0 };
uint32_t power=0;
diff --git a/TC1/main.h b/TC1/main.h
index 81b6c48..ff9f90b 100644
--- a/TC1/main.h
+++ b/TC1/main.h
@@ -4,7 +4,7 @@
#include "mico.h"
#include "MiCOKit_EXT.h"
-#define VERSION "v0.8"
+#define VERSION "v0.9"
#define TYPE 1
#define TYPE_NAME "zTC1"
@@ -65,6 +65,8 @@ typedef struct
extern char rtc_init;
+
+extern uint32_t total_time;
extern char strMac[16];
extern uint32_t power;
extern system_config_t * sys_config;
diff --git a/TC1/user_mqtt_client.c b/TC1/user_mqtt_client.c
index 62b8e2b..a8e2f44 100644
--- a/TC1/user_mqtt_client.c
+++ b/TC1/user_mqtt_client.c
@@ -18,6 +18,9 @@
*
© COPYRIGHT 2014 MXCHIP Inc.
******************************************************************************
*/
+#define app_log(M, ...) custom_log("APP", M, ##__VA_ARGS__)
+#define mqtt_log(M, ...) custom_log("MQTT", M, ##__VA_ARGS__)
+
#include "main.h"
#include "mico.h"
#include "MQTTClient.h"
@@ -26,25 +29,6 @@
#include "user_mqtt_client.h"
#include "cJSON/cJSON.h"
-/******************************************************
- * Macros
- ******************************************************/
-
-#define app_log(M, ...) custom_log("APP", M, ##__VA_ARGS__)
-#define mqtt_log(M, ...) custom_log("MQTT", M, ##__VA_ARGS__)
-
-/******************************************************
- * Constants
- ******************************************************/
-
-#define MQTT_CLIENT_ID sys_config->micoSystemConfig.name
-#define MQTT_CLIENT_USERNAME user_config->mqtt_user
-#define MQTT_CLIENT_PASSWORD user_config->mqtt_password
-#define MQTT_CLIENT_KEEPALIVE 30
-#define MQTT_CLIENT_SUB_TOPIC1 "device/ztc1/set" // loop msg
-#define MQTT_CLIENT_PUB_TOPIC "device/ztc1/%s/state"
-#define MQTT_CMD_TIMEOUT 5000 // 5s
-#define MQTT_YIELD_TMIE 5000 // 5s
//#define MQTT_CLIENT_SSL_ENABLE // ssl
#define MAX_MQTT_TOPIC_SIZE (256)
@@ -82,10 +66,6 @@ REyPOFdGdhBY2P1FNRy0MDr6xr+D2ZOwxs63dG1nnAnWZg7qwoLgpZ4fESPD3PkA\r\n\
#endif // MQTT_CLIENT_SSL_ENABLE
-/******************************************************
- * Structures
- ******************************************************/
-
typedef struct
{
char topic[MAX_MQTT_TOPIC_SIZE];
@@ -96,26 +76,16 @@ typedef struct
uint32_t datalen;
} mqtt_recv_msg_t, *p_mqtt_recv_msg_t, mqtt_send_msg_t, *p_mqtt_send_msg_t;
-/******************************************************
- * Function Declarations
- ******************************************************/
-
static void mqtt_client_thread( mico_thread_arg_t arg );
static void messageArrived( MessageData* md );
-static OSStatus mqtt_msg_publish( Client *c, const char* topic, char qos, char retained,
- const unsigned char* msg,
- uint32_t msg_len );
+static OSStatus mqtt_msg_publish( Client *c, const char* topic, char qos, char retained, const unsigned char* msg, uint32_t msg_len );
-OSStatus user_send_handler( void *arg );
OSStatus user_recv_handler( void *arg );
OSStatus user_mqtt_send_plug_state( char plug_id );
void user_mqtt_hass_auto( char plug_id );
void user_mqtt_hass_auto_power( void );
-/******************************************************
- * Variables Definitions
- ******************************************************/
bool isconnect = false;
mico_queue_t mqtt_msg_send_queue = NULL;
@@ -127,17 +97,83 @@ static mico_timed_event_t mqtt_client_send_event;
char topic_state[MAX_MQTT_TOPIC_SIZE];
char topic_set[MAX_MQTT_TOPIC_SIZE];
-char hass_mqtt_flag;
-/******************************************************
- * Function Definitions
- ******************************************************/
+
+mico_timer_t timer_handle;
+static uint8_t status = 0;
+void user_mqtt_timer_func( void *arg )
+{
+ uint8_t *buf1 = NULL;
+ status++;
+ switch ( status )
+ {
+ case 1:
+ user_mqtt_hass_auto_power( );
+ break;
+ case 2:
+ user_mqtt_hass_auto( 0 );
+ break;
+ case 3:
+ user_mqtt_hass_auto( 1 );
+ break;
+ case 4:
+ user_mqtt_hass_auto( 2 );
+ break;
+ case 5:
+ user_mqtt_hass_auto( 3 );
+ break;
+ case 6:
+ user_mqtt_hass_auto( 4 );
+ break;
+ case 7:
+ user_mqtt_hass_auto( 5 );
+ break;
+ case 8:
+ user_mqtt_hass_auto_name( 0 );
+ break;
+ case 9:
+ user_mqtt_hass_auto_name( 1 );
+ break;
+ case 10:
+ user_mqtt_hass_auto_name( 2 );
+ break;
+ case 11:
+ user_mqtt_hass_auto_name( 3 );
+ break;
+ case 12:
+ user_mqtt_hass_auto_name( 4 );
+ break;
+ case 13:
+ user_mqtt_hass_auto_name( 5 );
+ break;
+ case 14:
+ user_mqtt_hass_auto_power_name( );
+ break;
+ case 15:
+
+ buf1 = malloc( 1024 ); //idx涓1浣嶆椂闀垮害涓24
+ if ( buf1 != NULL )
+ {
+ sprintf(
+ buf1,
+ "{\"mac\":\"%s\",\"version\":null,\"plug_0\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_1\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_2\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_3\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_4\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_5\":{\"on\":null,\"setting\":{\"name\":null}}}",
+ strMac );
+ user_function_cmd_received( 0, buf1 );
+ free( buf1 );
+ }
+ break;
+ default:
+ mico_stop_timer( &timer_handle );
+// mico_deinit_timer( &timer_handle );
+ break;
+ }
+}
/* Application entrance */
OSStatus user_mqtt_init( void )
{
OSStatus err = kNoErr;
- sprintf( topic_set, MQTT_CLIENT_SUB_TOPIC1, strMac );
+ sprintf( topic_set, MQTT_CLIENT_SUB_TOPIC1 );
sprintf( topic_state, MQTT_CLIENT_PUB_TOPIC, strMac );
#ifdef MQTT_CLIENT_SSL_ENABLE
@@ -165,9 +201,6 @@ OSStatus user_mqtt_init( void )
err = mico_rtos_create_worker_thread( &mqtt_client_worker_thread, MICO_APPLICATION_PRIORITY, 0x800, 5 );
require_noerr_string( err, exit, "ERROR: Unable to start the mqtt client worker thread." );
-// /* Trigger a period send event */
-// mico_rtos_register_timed_event( &mqtt_client_send_event, &mqtt_client_worker_thread, user_send_handler, 2000, NULL );
-
exit:
if ( kNoErr != err ) app_log("ERROR, app thread exit err: %d", err);
return err;
@@ -280,7 +313,6 @@ void mqtt_client_thread( mico_thread_arg_t arg )
mqtt_log("ERROR: MQTT network connection err=%d, reconnect after 3s...", rc);
}
- hass_mqtt_flag = PLUG_NUM;
mqtt_log("MQTT network connection success!");
/* 2. init mqtt client */
@@ -293,9 +325,9 @@ void mqtt_client_thread( mico_thread_arg_t arg )
/* 3. create mqtt client connection */
connectData.willFlag = 0;
connectData.MQTTVersion = 4; // 3: 3.1, 4: v3.1.1
- connectData.clientID.cstring = MQTT_CLIENT_ID;
- connectData.username.cstring = MQTT_CLIENT_USERNAME;
- connectData.password.cstring = MQTT_CLIENT_PASSWORD;
+ connectData.clientID.cstring = strMac;
+ connectData.username.cstring = user_config->mqtt_user;
+ connectData.password.cstring = user_config->mqtt_password;
connectData.keepAliveInterval = MQTT_CLIENT_KEEPALIVE;
connectData.cleansession = 1;
@@ -310,18 +342,9 @@ void mqtt_client_thread( mico_thread_arg_t arg )
mqtt_log("MQTT client subscribe success! recv_topic=[%s].", topic_set);
/*4.1 杩炴帴鎴愬姛鍚庡厛鏇存柊鍙戦佷竴娆℃暟鎹*/
isconnect = true;
- uint8_t *buf1 = NULL;
- buf1 = malloc( 1024 ); //idx涓1浣嶆椂闀垮害涓24
- if ( buf1 != NULL )
- {
- sprintf(
- buf1,
- "{\"mac\":\"%s\",\"version\":null,\"plug_0\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_1\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_2\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_3\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_4\":{\"on\":null,\"setting\":{\"name\":null}},\"plug_5\":{\"on\":null,\"setting\":{\"name\":null}}}",
- strMac );
- user_function_cmd_received( 0, buf1 );
- free( buf1 );
- }
+ mico_init_timer( &timer_handle, 150, user_mqtt_timer_func, &arg );
+ mico_start_timer( &timer_handle );
/* 5. client loop for recv msg && keepalive */
while ( 1 )
{
@@ -340,13 +363,6 @@ void mqtt_client_thread( mico_thread_arg_t arg )
no_mqtt_msg_exchange = false;
}
- if ( hass_mqtt_flag > 0 )
- {
- if ( hass_mqtt_flag == PLUG_NUM ) user_mqtt_hass_auto_power( );
- hass_mqtt_flag--;
- user_mqtt_hass_auto( hass_mqtt_flag );
- user_mqtt_send_plug_state( hass_mqtt_flag );
- }
/* recv msg from user worker thread to be sent to server */
if ( FD_ISSET( msg_send_event_fd, &readfds ) )
{
@@ -379,7 +395,15 @@ void mqtt_client_thread( mico_thread_arg_t arg )
}
MQTT_reconnect:
+
mqtt_log("Disconnect MQTT client, and reconnect after 5s, reason: mqtt_rc = %d, err = %d", rc, err );
+
+ if (&timer_handle !=NULL && mico_rtos_is_timer_running( &timer_handle ) )
+ {
+ mico_stop_timer( &timer_handle );
+// mico_deinit_timer( &timer_handle );
+ }
+
mqtt_client_release( &c, &n );
isconnect = false;
user_led_set( -1 );
@@ -512,27 +536,44 @@ void user_mqtt_hass_auto( char plug_id )
if ( send_buf != NULL && topic_buf != NULL )
{
sprintf( topic_buf, "homeassistant/switch/%s/plug_%d/config", strMac, plug_id );
- sprintf( send_buf,
- "{"
- "\"name\":\"%s\","
- "\"state_topic\":\"homeassistant/switch/%s/plug_%d/state\","
- "\"command_topic\":\"device/ztc1/set\","
- "\"payload_on\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":1}}\","
- "\"payload_off\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":0}}\""
- "}",
- user_config->plug[plug_id].name,
- strMac,
- plug_id,
- strMac,
- plug_id,
- strMac,
- plug_id );
+ sprintf( send_buf, "{"
+ "\"name\":\"zTC1_plug%d_%s\","
+ "\"stat_t\":\"homeassistant/switch/%s/plug_%d/state\","
+ "\"cmd_t\":\"device/ztc1/set\","
+ "\"pl_on\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":1}}\","
+ "\"pl_off\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":0}}\""
+ "}\0",
+ plug_id, strMac + 8, strMac, plug_id, strMac, plug_id, strMac, plug_id );
user_mqtt_send_topic( topic_buf, send_buf, 1 );
}
if ( send_buf ) free( send_buf );
if ( topic_buf ) free( topic_buf );
}
+void user_mqtt_hass_auto_name( char plug_id )
+{
+ uint8_t *send_buf = NULL;
+ uint8_t *topic_buf = NULL;
+ send_buf = (uint8_t *) malloc( 300 );
+ topic_buf = (uint8_t *) malloc( 64 );
+ if ( send_buf != NULL && topic_buf != NULL )
+ {
+ sprintf( topic_buf, "homeassistant/switch/%s/plug_%d/config", strMac, plug_id );
+ sprintf( send_buf, "{"
+ "\"name\":\"%s\","
+ "\"stat_t\":\"homeassistant/switch/%s/plug_%d/state\","
+ "\"cmd_t\":\"device/ztc1/set\","
+ "\"pl_on\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":1}}\","
+ "\"pl_off\":\"{\\\"mac\\\":\\\"%s\\\",\\\"plug_%d\\\":{\\\"on\\\":0}}\""
+ "}\0",
+ user_config->plug[plug_id].name, strMac, plug_id, strMac, plug_id, strMac, plug_id );
+ user_mqtt_send_topic( topic_buf, send_buf, 0 );
+ }
+ if ( send_buf )
+ free( send_buf );
+ if ( topic_buf )
+ free( topic_buf );
+}
//hass mqtt鑷姩鍙戠幇鏁版嵁鍔熺巼鍙戦
void user_mqtt_hass_auto_power( void )
{
@@ -544,19 +585,49 @@ void user_mqtt_hass_auto_power( void )
if ( send_buf != NULL && topic_buf != NULL )
{
sprintf( topic_buf, "homeassistant/sensor/%s/power/config", strMac );
- sprintf( send_buf,
- "{"
- "\"name\":\"鍔熺巼\","
+ sprintf( send_buf, "{"
+ "\"name\":\"zTC1_power_%s\","
+ "\"state_topic\":\"homeassistant/sensor/%s/power/state\","
+ "\"unit_of_measurement\":\"W\","
+ "\"icon\":\"mdi:gauge\","
+ "\"value_template\":\"{{ value_json.power }}\""
+ "}",
+ strMac + 8, strMac );
+
+ user_mqtt_send_topic( topic_buf, send_buf, 1 );
+ }
+ if ( send_buf ) free( send_buf );
+ if ( topic_buf ) free( topic_buf );
+}
+void user_mqtt_hass_auto_power_name( void )
+{
+ uint8_t *send_buf = NULL;
+ uint8_t *topic_buf = NULL;
+ send_buf = (uint8_t *) malloc( 300 ); //
+ topic_buf = (uint8_t *) malloc( 64 ); //
+ if ( send_buf != NULL && topic_buf != NULL )
+ {
+ sprintf( topic_buf, "homeassistant/sensor/%s/power/config", strMac );
+ sprintf( send_buf, "{"
+ "\"name\":\"zTC1xxxxxx\","
"\"state_topic\":\"homeassistant/sensor/%s/power/state\","
"\"unit_of_measurement\":\"W\","
"\"icon\":\"mdi:gauge\","
"\"value_template\":\"{{ value_json.power }}\""
"}",
strMac );
+ send_buf[13] = 0xe5;
+ send_buf[14] = 0x8a;
+ send_buf[15] = 0x9f;
+ send_buf[16] = 0xe7;
+ send_buf[17] = 0x8e;
+ send_buf[18] = 0x87;
user_mqtt_send_topic( topic_buf, send_buf, 1 );
}
- if ( send_buf ) free( send_buf );
- if ( topic_buf ) free( topic_buf );
+ if ( send_buf )
+ free( send_buf );
+ if ( topic_buf )
+ free( topic_buf );
}
void user_mqtt_hass_power( void )
@@ -569,7 +640,7 @@ void user_mqtt_hass_power( void )
if ( send_buf != NULL && topic_buf != NULL )
{
sprintf( topic_buf, "homeassistant/sensor/%s/power/state", strMac );
- sprintf( send_buf, "{\"power\":\"%d.%d\"}", power/10,power%10 );
+ sprintf( send_buf, "{\"power\":\"%d.%d\"}", power / 10, power % 10 );
user_mqtt_send_topic( topic_buf, send_buf, 0 );
}
if ( send_buf ) free( send_buf );
diff --git a/TC1/user_mqtt_client.h b/TC1/user_mqtt_client.h
index 8fef47f..05fde31 100644
--- a/TC1/user_mqtt_client.h
+++ b/TC1/user_mqtt_client.h
@@ -4,6 +4,11 @@
#include "mico.h"
+#define MQTT_CLIENT_KEEPALIVE 30
+#define MQTT_CLIENT_SUB_TOPIC1 "device/ztc1/set"
+#define MQTT_CLIENT_PUB_TOPIC "device/ztc1/%s/state"
+#define MQTT_CMD_TIMEOUT 5000 // 5s
+#define MQTT_YIELD_TMIE 5000 // 5s
extern OSStatus user_mqtt_init(void);
@@ -11,5 +16,8 @@ extern OSStatus user_mqtt_send( char *arg );
extern bool user_mqtt_isconnect(void);
extern OSStatus user_mqtt_send_plug_state( char plug_id );
extern void user_mqtt_hass_auto( char plug_id );
+extern void user_mqtt_hass_auto_name(char plug_id);
extern void user_mqtt_hass_power( void );
+extern void user_mqtt_hass_auto_power( void );
+extern void user_mqtt_hass_auto_power_name(void);
#endif
diff --git a/TC1/user_rtc.c b/TC1/user_rtc.c
index 39efc45..475de98 100644
--- a/TC1/user_rtc.c
+++ b/TC1/user_rtc.c
@@ -117,7 +117,7 @@ void rtc_thread( mico_thread_arg_t arg )
uint32_t power_last = 0xffffffff;
mico_utc_time_t utc_time;
-
+ mico_utc_time_t utc_time_last;
while ( 1 )
{ //上电后连接了wifi才开始走时否则等待连接
micoWlanGetLinkStatus( &LinkStatus );
@@ -138,6 +138,14 @@ void rtc_thread( mico_thread_arg_t arg )
{
mico_time_get_utc_time( &utc_time );
utc_time += 28800;
+
+ if(utc_time_last!=utc_time)
+ {
+ utc_time_last==utc_time;
+ total_time++;
+ }
+
+
struct tm * currentTime = localtime( (const time_t *) &utc_time );
rtc_time.sec = currentTime->tm_sec;
rtc_time.min = currentTime->tm_min;
@@ -255,7 +263,7 @@ void rtc_thread( mico_thread_arg_t arg )
power_buf = malloc( 128 ); //
if ( power_buf != NULL )
{
- sprintf( power_buf, "{\"mac\":\"%s\",\"power\":\"%d.%d\"}", strMac, power/10,power%10 );
+ sprintf( power_buf, "{\"mac\":\"%s\",\"power\":\"%d.%d\",\"total_time\":%d}", strMac, power/10,power%10,total_time );
user_send( 0, power_buf );
free( power_buf );
}
diff --git a/build/TC1@MK3031@moc/binary/TC1@MK3031@moc.all.bin b/build/TC1@MK3031@moc/binary/TC1@MK3031@moc.all.bin
index 458d4fe6b4b20d57fb704c67d55db2263c7aa7c4..71d72e6ed7734ccb26c3802f3c672e39c62b8f51 100644
GIT binary patch
delta 22219
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