ソースを参照

本地 OneNet_API.py 成功下发命令给 esp

mrh 3 年 前
コミット
7a7957f91e
7 ファイル変更136 行追加44 行削除
  1. 4 1
      esp8266/debug.py
  2. 49 16
      esp8266/esp_mqtt.py
  3. 9 2
      esp8266/main.py
  4. 23 10
      esp8266/mywifi.py
  5. 25 6
      esp8266/test.py
  6. 20 5
      python38/OneNet_API.py
  7. 6 4
      python38/test.py

+ 4 - 1
esp8266/debug.py

@@ -1,3 +1,6 @@
 import main
 
-main.device.mqtt.upload_timer_callback()
+main.device.mqtt.publish_timer_callback()
+device.mqtt.upload_stop()
+device.mqtt.upload_start(2000)
+device.mqtt.client.subscribe("$sys/522417/esp8266/#", qos=1)

+ 49 - 16
esp8266/esp_mqtt.py

@@ -5,8 +5,7 @@ from machine import Pin
 from machine import Timer
 import ustruct as struct
 from umqtt.simple import MQTTClient
-
-led = Pin(2, Pin.OUT, value=0)
+import re
 
 SERVER = 'mqtts.heclouds.com'  # 服务器地址
 PRO_ID = '522417'  # 产品ID
@@ -25,30 +24,43 @@ class MqttOneNet():
         # 暂未用到
         self.accesskey = ""
         self.device_id = ""
-        self.client = self.client_init()
+        self.client = None
+        self.client_init()
         self.data_point_id = 0
-        self.upload_init()
+        # self.upload_start(2000)
 
-    def upload_init(self):
-        self.data_point_id = 0
+    def upload_start(self, ms):
         self.tim = Timer(-1)
         # 每 2000ms 定时回调一次 self.upload_data()
-        self.tim.init(period=2000, mode=Timer.PERIODIC,
+        self.tim.init(period=ms, mode=Timer.PERIODIC,
                       callback=self.publish_timer_callback)
-        print("init finish, start upload_data")
+        print("start upload_data")
 
+    def upload_stop(self):
+        self.tim.deinit()
+    
     def client_init(self):
-        client = MQTTClient(client_id=self.device_name, server=self.broker_addr, port=self.broker_port, user=self.product_id,
+        self.client = MQTTClient(client_id=self.device_name, server=self.broker_addr, port=self.broker_port, user=self.product_id,
                             password=self.password, keepalive=360)  # create a mqtt client
-        client.connect()  # connect mqtt
+        self.client.connect()  # connect mqtt
         print("mqtt connect")
-        client.set_callback(self.client_msg_callback)
+        self.client.set_callback(self.client_msg_callback)
+
+        # 每 50ms 定时回调一次检查消息是否到来
+        self.tim = Timer(-2)
+        self.tim.init(period=50, mode=Timer.PERIODIC,
+                      callback=self.check_mag_callback)
         # 订阅所有消息
         topic = f"$sys/{self.product_id}/{self.device_name}/#"
-        client.subscribe(topic)
+        self.client.subscribe(topic, qos=1)
         print("subscribed to %s topic" % (topic))
-        return client
+        
+        print("client init finish")
+
+    def check_mag_callback(self, timer):
+        self.client.check_msg()
 
+    
     # timer 是定时器回调函数需要的参数,实际上是定时器本身(self),如果没有这个参数,定时器会一直打印一个错误
     # http://docs.micropython.org/en/latest/library/machine.Timer.html#machine-timer
     def publish_timer_callback(self, timer):
@@ -59,13 +71,35 @@ class MqttOneNet():
         print("------------- publish ------------- \n")
         print("topic:%s\n" % topic_publish)
         print("payload:%s\n" % payload)
-        self.client.publish(topic=topic_publish, msg=payload, qos=1)
+        self.publish(topic_publish, payload, qos=1)
+
+    def response_cmd(self, topic_list, msg):
+        if topic_list[4] == 'request':
+            print("receive cmd:", msg)
+            
+            cmdid = topic_list[5]
+            response_topic = f"$sys/{self.product_id}/{self.device_name}/cmd/response/{cmdid}"
+            payload = "12gfok"
+            print("------------- response ------------- \n")
+            print("topic:%s\n" % response_topic)
+            print("payload:%s\n" % payload)
+            self.publish(response_topic, payload)
 
     def client_msg_callback(self, topic, msg):
         print("\n------------- receive ------------- \n")
         print("topic:%s\n" % topic)
         print("payload:%s\n" % msg)
+        
+        topic_list = str(topic, 'utf8').split('/')
+        # 收到服务器命令:$sys/{pid}/{device-name}/cmd/request/{cmdid}
+        if topic_list[3] == 'cmd':
+            self.response_cmd(topic_list, msg)
 
+    def publish(self, topic, msg, retain=False, qos=0):
+        # 必须转换成bytes类型发送
+        msg = bytes("{}".format(msg), 'utf8')
+        self.client.publish(topic=topic, msg=msg, retain=retain, qos=qos)
+    
     # 获取板子数据,用于上传到服务器
     def get_upload_data(self):
         self.data_point_id += 1
@@ -83,7 +117,6 @@ class MqttOneNet():
                 }]
             }
         }
-        message = bytes("{}".format(message), 'utf8')
         return message
 
     def get_temperature(self):
@@ -105,6 +138,6 @@ class MqttOneNet():
 # device = MqttOneNet()
 if __name__ == '__main__':
     try:
-        MqttOneNet()
+        mq = MqttOneNet()
     except Exception as e:
         print(e)

+ 9 - 2
esp8266/main.py

@@ -1,9 +1,16 @@
-import mywifi
+from mywifi import MyWifi
 from esp_mqtt import MqttOneNet
 
 class Device():
+    _instance = None
+    # 单例模式:WiFi实例化只能有一次,实例化多个 mywifi 对象将始终返回同一个-
+    def __new__(cls, *args, **kwargs):
+        if cls._instance is None:
+            cls._instance = super().__new__(cls)
+        return cls._instance   # 返回的是内存地址
+
     def __init__(self) -> None:
-        self.wlan = mywifi.do_connect()
+        self.wifi = MyWifi()
         self.mqtt = MqttOneNet()
 
 # if __name__ == '__main__':

+ 23 - 10
esp8266/mywifi.py

@@ -1,16 +1,29 @@
 import network
+from machine import Timer
 SSID = "Xiaomi_eng"
 PASSWORD = "88888888"
 
+class MyWifi():
+    _instance = None
+    # 单例模式:WiFi实例化只能有一次,实例化多个 mywifi 对象将始终返回同一个-
+    def __new__(cls, *args, **kwargs):
+        if cls._instance is None:
+            cls._instance = super().__new__(cls)
+        return cls._instance   # 返回的是内存地址
 
-wlan = network.WLAN(network.STA_IF)
+    def __init__(self, ssid=SSID, password=PASSWORD) -> None:
+        self.ssid = ssid
+        self.password = PASSWORD
+        self.wlan = network.WLAN(network.STA_IF)
+        self.wlan.active(True)
+        self.tim = Timer(0)
+        # 每 2000ms 定时回调一次 self.upload_data()
+        self.tim.init(period=5000, mode=Timer.PERIODIC,callback=self.do_connect)
 
-def do_connect():
-    wlan.active(True)
-    if not wlan.isconnected():
-        print('connecting to network...')
-        wlan.connect(SSID, PASSWORD)
-        while not wlan.isconnected():
-            pass
-    print('network config:', wlan.ifconfig())
-    return wlan
+    def do_connect(self, timer):
+        if not self.wlan.isconnected():
+            print('connecting to network...')
+            self.wlan.connect(SSID, PASSWORD)
+            while not self.wlan.isconnected():
+                pass
+            print('network config:', self.wlan.ifconfig())

+ 25 - 6
esp8266/test.py

@@ -4,6 +4,8 @@ from machine import Timer
 import struct
 import os
 import time
+import re
+from esp_mqtt import MQTTClient
 
 class Client():
     def __init__(self):
@@ -21,10 +23,10 @@ class Test():
         self.timer = Timer(-1)
         print("self", self)
         
-        self.client = Client()
-        # # 每 2000ms 定时回调一次 self.upload_data()
-        self.timer.init(period=2000, mode=Timer.PERIODIC, callback=self.publish_timer_callback)
-        self.count = 0
+        # self.client = Client()
+        # # # 每 2000ms 定时回调一次 self.upload_data()
+        # self.timer.init(period=2000, mode=Timer.PERIODIC, callback=self.publish_timer_callback)
+        # self.count = 0
         
     def publish_timer_callback(self, timer):
         self.count += 1
@@ -34,8 +36,25 @@ class Test():
         print("self.client")
         print("self.timer:", self.timer)
     
+    def receive_cmd_callback(self, topic_list, msg):
+        if topic_list[4] == 'request':
+            cmdid = topic_list[5]
+            response_topic = f"$sys/{pid}/{device-name}/cmd/response/{cmdid}"
+            print(response_topic)
         
+        
+    def client_msg_callback(self, topic, msg):
+        print("\n------------- receive ------------- \n")
+        print("topic:%s\n" % topic)
+        print("payload:%s\n" % msg)
+        re.compile("$sys/(\d+)/(w+)/(w+)/(w+)")
+        topic_list = topic.split('/')
+        # 收到服务器命令:$sys/{pid}/{device-name}/cmd/request/{cmdid}
+        if topic_list[3] == 'cmd':
+            self.receive_cmd_callback(topic_list, msg)
 
-    
-test_ob = Test()
+t = Test()
+topick = "$sys/522417/emq_online/cmd/request/c9f24219-1ec2-4e21-9b37-4673c5ca3db7"
+payload = "open"
+t.client_msg_callback(topick, payload)
 

+ 20 - 5
python38/OneNet_API.py

@@ -1,5 +1,6 @@
 import requests
 import json
+import base64
 
 # 因为设备名是唯一的,加上 token 中有产品ID,因此很容易仅通过设备名就可以查询设备信息
 DEVICE_NAME = "emq_online"
@@ -16,6 +17,8 @@ class Api_OneNet():
         headers = {
             'Authorization': self.token,
             }
+        print("GET url:", url)
+        print("GET headers:", headers)
         response = requests.request("GET", url, headers=headers)
         print(type(response))
         device_info = json.dumps(response.json(), indent=2, ensure_ascii=False)
@@ -26,20 +29,32 @@ class Api_OneNet():
         url = self.api_addr + f'/mqtt/v1/devices/reg'
         # TODO
     
-    def device_cmd(self, device_id):
+    def device_cmd(self, device_id, dat):
         url = self.api_addr + f'/v1/synccmds?device_id={device_id}&timeout=30'
         headers = {
             'Authorization': self.token,
         }
-        response = requests.request("POST", url, headers=headers, data="open")
-        res = json.dumps(response.json(), indent=2, ensure_ascii=False)
-        print(res)
+        print("POST url:", url)
+        print("POST headers:", headers)
+        # 返回一个对象, response.content 得到其内容,数据类型为 bytes
+        response = requests.post(url, headers=headers, data=dat)
+        print(type(response.json()), "\n", response.json())
+        # response.json() 类型是字典
+        res = response.json()        
+        # 命令发送消息成功,设备有应答
+        if res["errno"] == 0:
+            # 收到设备回复的信息内容格式是base64,需要解码
+            res["data"]["cmd_resp"] = base64.b64decode(res["data"]["cmd_resp"])
+        # 设备没有应答
+        else:
+            print("error")
+        print("res:\n", res)
         return res
 
     
 if __name__ == '__main__':
     api = Api_OneNet()
-    api.device_cmd('952659214')
+    api.device_cmd('951045379', 'open')
     
 '''
 <class 'requests.models.Response'>

+ 6 - 4
python38/test.py

@@ -1,14 +1,16 @@
-
+import base64
 class Test():
     def __init__(self) -> None:
-        print("Test() init")
         self.ok = 1
     
     def upload_data(self):
         print("upload")
         self.ok += 1
-    
-test_ob = Test()
+
+       
+b64 =   "b2s="
+print(str(base64.b64decode(b64)))
+# test_ob = Test()
 dat = {
   'id': 1, 
   'dp':{