Quellcode durchsuchen

esp8266 实现数据定时上传与接收应答

mrh vor 3 Jahren
Ursprung
Commit
ef7e4f7152

+ 3 - 0
esp8266/debug.py

@@ -0,0 +1,3 @@
+import main
+
+main.device.mqtt.upload_timer_callback()

+ 6 - 0
esp8266/demo/files_sys.py

@@ -0,0 +1,6 @@
+import os
+
+#print(os.listdir())
+#print(help("modules"))
+# f = open('esp_mqtt.py')
+# print(f.read(30))

+ 6 - 18
esp_mqtt.py → esp8266/demo/my_mqtt.py

@@ -1,23 +1,15 @@
-# Hardware Platform: FireBeetle-ESP32
-# Result: input MQTTlibrary and remote controls LED by mqtt communication.
-import uos
-from umqtt.simple import MQTTClient
+import os
 from machine import Pin
-import network
-import time
-
-led = Pin(2, Pin.OUT, value=0)
+from machine import Timer
+import ustruct as struct
+from umqtt.simple import MQTTClient
 
 SERVER = 'mqtts.heclouds.com'  # 服务器地址
 PRO_ID = '522417'  # 产品ID
 DEV_NAME = 'esp8266'  # 设备名称
-accesskey = "dgEP7iOL2/1kVNc1ykDvIhXSVqhb0tLnKinjU2RYpDs="  # 设备秘钥
-
-TOPIC = b"esp-status"
-username = PRO_ID
+# accesskey = "dgEP7iOL2/1kVNc1ykDvIhXSVqhb0tLnKinjU2RYpDs="  # 设备秘钥
 password = "version=2018-10-31&res=products%2F522417&et=1685551369&method=sha1&sign=9l9gkFQx7A%2B7B3fu8uU%2F089azps%3D"
 
-
 def data(ds_id, value):
     message = {
         "id": int(ds_id),
@@ -70,8 +62,4 @@ def my_mqtt():
 
     finally:
         if(client is not None):
-            client.disconnect()
-            
-            
-if __name__ == '__main__':
-    my_mqtt()
+            client.disconnect()

+ 0 - 0
esp_http.py → esp8266/esp_http.py


+ 110 - 0
esp8266/esp_mqtt.py

@@ -0,0 +1,110 @@
+# Hardware Platform: FireBeetle-ESP32
+# Result: input MQTTlibrary and remote controls LED by mqtt communication.
+import os
+from machine import Pin
+from machine import Timer
+import ustruct as struct
+from umqtt.simple import MQTTClient
+
+led = Pin(2, Pin.OUT, value=0)
+
+SERVER = 'mqtts.heclouds.com'  # 服务器地址
+PRO_ID = '522417'  # 产品ID
+DEV_NAME = 'esp8266'  # 设备名称
+# accesskey = "dgEP7iOL2/1kVNc1ykDvIhXSVqhb0tLnKinjU2RYpDs="  # 设备秘钥
+password = "version=2018-10-31&res=products%2F522417&et=1685551369&method=sha1&sign=9l9gkFQx7A%2B7B3fu8uU%2F089azps%3D"
+
+class MqttOneNet():
+    def __init__(self, device_name=DEV_NAME) -> None:
+        self.broker_addr = 'mqtts.heclouds.com'
+        self.broker_port = 1883
+        self.product_id = "522417"
+        # 由 token 算法得出,有效期为 2023年5月31日01:41:21
+        self.password = "version=2018-10-31&res=products%2F522417&et=1685551369&method=sha1&sign=9l9gkFQx7A%2B7B3fu8uU%2F089azps%3D"
+        self.device_name = device_name
+        # 暂未用到
+        self.accesskey = ""
+        self.device_id = ""
+        self.client = self.client_init()
+        self.data_point_id = 0
+        self.upload_init()
+
+    def upload_init(self):
+        self.data_point_id = 0
+        self.tim = Timer(-1)
+        # 每 2000ms 定时回调一次 self.upload_data()
+        self.tim.init(period=2000, mode=Timer.PERIODIC,
+                      callback=self.publish_timer_callback)
+        print("init finish, start upload_data")
+
+    def client_init(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
+        print("mqtt connect")
+        client.set_callback(self.client_msg_callback)
+        # 订阅所有消息
+        topic = f"$sys/{self.product_id}/{self.device_name}/#"
+        client.subscribe(topic)
+        print("subscribed to %s topic" % (topic))
+        return client
+
+    # timer 是定时器回调函数需要的参数,实际上是定时器本身(self),如果没有这个参数,定时器会一直打印一个错误
+    # http://docs.micropython.org/en/latest/library/machine.Timer.html#machine-timer
+    def publish_timer_callback(self, timer):
+        topic_publish = '$sys/%s/%s/dp/post/json' % (
+            self.product_id, self.device_name)
+        payload = self.get_upload_data()
+        
+        print("------------- publish ------------- \n")
+        print("topic:%s\n" % topic_publish)
+        print("payload:%s\n" % payload)
+        self.client.publish(topic=topic_publish, msg=payload, qos=1)
+
+    def client_msg_callback(self, topic, msg):
+        print("\n------------- receive ------------- \n")
+        print("topic:%s\n" % topic)
+        print("payload:%s\n" % msg)
+
+    # 获取板子数据,用于上传到服务器
+    def get_upload_data(self):
+        self.data_point_id += 1
+        message = {
+            "id": int(self.data_point_id),
+            "dp": {
+                "sensor": [{      # 距离传感器采集的数据
+                    "v": {
+                        "temperature": self.get_temperature(),
+                        "humidity": self.get_humidity()
+                    }
+                }],
+                "system": [{        
+                    "v": self.get_system()
+                }]
+            }
+        }
+        message = bytes("{}".format(message), 'utf8')
+        return message
+
+    def get_temperature(self):
+        return struct.unpack('@H', os.urandom(2))[0]
+    
+    def get_humidity(self):
+        return struct.unpack('@H', os.urandom(2))[0]
+
+    def get_system(self):
+        info = {}
+        info["power"]=os.urandom(1)[0] % 42
+        gps_location = struct.unpack('@BBBB', os.urandom(4))
+        info["GPS"] = "%d°%d'N',%d°%d'E" % (gps_location[0], gps_location[1], gps_location[2], gps_location[3])
+        info["altitude"] = struct.unpack('@H', os.urandom(2))[0]
+        return info
+    
+
+            
+# device = MqttOneNet()
+if __name__ == '__main__':
+    try:
+        MqttOneNet()
+    except Exception as e:
+        print(e)

+ 0 - 0
led.py → esp8266/led.py


+ 11 - 0
esp8266/main.py

@@ -0,0 +1,11 @@
+import mywifi
+from esp_mqtt import MqttOneNet
+
+class Device():
+    def __init__(self) -> None:
+        self.wlan = mywifi.do_connect()
+        self.mqtt = MqttOneNet()
+
+# if __name__ == '__main__':
+device = Device()
+#device.mqtt.publish_timer_callback()

+ 3 - 1
mywifi.py → esp8266/mywifi.py

@@ -1,9 +1,10 @@
 import network
 SSID = "Xiaomi_eng"
 PASSWORD = "88888888"
-wlan = network.WLAN(network.STA_IF)
 
 
+wlan = network.WLAN(network.STA_IF)
+
 def do_connect():
     wlan.active(True)
     if not wlan.isconnected():
@@ -12,3 +13,4 @@ def do_connect():
         while not wlan.isconnected():
             pass
     print('network config:', wlan.ifconfig())
+    return wlan

+ 0 - 0
readme.md → esp8266/readme.md


+ 41 - 0
esp8266/test.py

@@ -0,0 +1,41 @@
+# import mywifi
+from machine import Timer
+# import esp_mqtt
+import struct
+import os
+import time
+
+class Client():
+    def __init__(self):
+        self.data = os.urandom(1)
+    
+    def push(self):
+        self.data=os.urandom(1)
+        print("upload:", self.data)
+
+    
+class Test():
+    def __init__(self) -> None:
+        temp = struct.unpack('!BBBB', os.urandom(4))
+        print(temp)
+        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
+        
+    def publish_timer_callback(self, timer):
+        self.count += 1
+        print("upload:", self.count)
+        print("self", self.client)
+        self.client.push()
+        print("self.client")
+        print("self.timer:", self.timer)
+    
+        
+
+    
+test_ob = Test()
+

+ 0 - 6
main.py

@@ -1,6 +0,0 @@
-import mywifi
-import esp_mqtt
-
-if __name__ == '__main__':
-    mywifi.do_connect()
-    esp_mqtt.my_mqtt()

+ 0 - 0
python38/Onet_API_https.py → python38/OneNet_API.py


+ 6 - 0
python38/board.py

@@ -0,0 +1,6 @@
+from pyboard import Pyboard
+pyb = Pyboard('COM22', 115200)
+pyb.enter_raw_repl()
+ret = pyb.exec('print(1+1)')
+print(ret)
+pyb.exit_raw_repl()

+ 0 - 0
python38/OneNet_communicate-RaspberryPi.py → python38/communicate-RaspberryPi.py


+ 27 - 24
python38/OneNet_communicate.py → python38/communicate.py

@@ -1,11 +1,10 @@
 # -*- coding: utf-8 -*-
 # pip install paho-mqtt
-import base64
-import hmac
 import paho.mqtt.client as mqtt
 import time
 from urllib.parse import quote
-from OneNet_token import cal_token
+from mylib import cal_token, payload_data
+import random
 
 SERVER = 'mqtts.heclouds.com'
 PRO_ID = "522417" #产品ID
@@ -26,26 +25,6 @@ def on_message(client, userdata, msg):
 def on_publish(client, userdata, mid):
     print(str(mid))
 
-import random
-def data(ds_id,value):
-    message = {
-        "id": int(ds_id),
-        "dp": {
-            "count": [{      # 距离传感器采集的数据
-                "v": value
-            }],
-            "random": [{        # Python产生的随机数
-                "v": random.randint(20,80)
-            }],
-            "talk": [{        # Python产生的随机数
-                "v": "fuck you bitch!%d"%(value*random.randint(20,80))
-            }]
-        }
-    }
-    # message = json.dumps(message).encode('ascii')
-    # print("publish json:", bytes("{}".format(message), 'ascii'))
-    message = bytes("{}".format(message), 'ascii')
-    return message
 
 def main():
     # password = cal_token(PRO_ID, accesskey)
@@ -70,7 +49,31 @@ def main():
     count = 0
     while True:
         count += 1
-        payload = data(count, random.randint(0, 100))
+        dat = {
+                "temperatrue": [{
+                    "v": random.randint(0, 100),
+                }],
+                "power": [{
+                    "v": random.randint(33, 55)/10,
+                    "t": time.time()
+                }],
+                "status": [{
+                    "v": {
+                        "color": "blue",
+                        "led1": "on",
+                        "led2": "off",
+                    }
+                },
+                    {
+                    "v": {
+                        "color": "red"
+                    },
+                    "t": time.time()
+                }
+                ]
+            }
+        
+        payload = payload_data(count, dat)
         client.publish(topic=topic_publish, payload=payload, qos=1)
         print("topic_publish: ", topic_publish)
         print("payload: ", payload)

+ 0 - 0
python38/OneNet_connect.py → python38/connect.py


+ 109 - 0
python38/mqtt_onenet.py

@@ -0,0 +1,109 @@
+# -*- coding: utf-8 -*-
+# pip install paho-mqtt
+import paho.mqtt.client as mqtt
+import time
+from urllib.parse import quote
+from mylib import cal_token, payload_data
+import random
+
+SERVER = 'mqtts.heclouds.com'
+PRO_ID = "522417"  # 产品ID
+DEV_NAME = 'local_python'
+
+# 当客户端收到来自服务器的CONNACK响应时的回调。也就是申请连接,服务器返回结果是否成功等
+class MqttOneNet():
+    def __init__(self, device_name) -> None:
+        self.broker_addr = 'mqtts.heclouds.com'
+        self.broker_port = 1883
+        self.product_id = "522417"
+        # 由 token 算法得出,有效期为 2023年5月31日01:41:21
+        self.password = "version=2018-10-31&res=products%2F522417&et=1685551369&method=sha1&sign=9l9gkFQx7A%2B7B3fu8uU%2F089azps%3D"
+        self.device_name = 'local_python'
+        # 暂未用到
+        self.accesskey = ""
+        self.device_id = ""
+        self.client_init()
+        self.publish_dat()
+        
+    def publish_dat(self):
+        topic_publish = '$sys/%s/%s/dp/post/json' % (
+            self.product_id, self.device_name)
+        count = 0
+        while True:
+            count += 1
+            dat = self.read_dat()
+            payload = self.payload_format(count, dat)
+            self.client.publish(topic=topic_publish, payload=payload, qos=1)
+            print("topic_publish: ", topic_publish)
+            print("payload: ", payload)
+            print("-------------------------------------------------------------------------------")
+            time.sleep(3)
+            
+    def read_dat(self):
+        dat = {
+            "temperatrue": [{
+                            "v": random.randint(0, 100),
+                            }],
+            "power": [{
+                "v": random.randint(33, 55)/10,
+                "t": time.time()
+            }],
+            "status": [{
+                "v": {
+                    "color": "blue",
+                    "led1": "on",
+                    "led2": "off",
+                }
+            },
+                {
+                "v": {
+                    "color": "red"
+                },
+                "t": time.time()
+            }
+            ]
+        }
+        return dat
+    '''
+    publish 时,OneNet 对 payload 数据的格式要求:
+    dictionaries 必须为字典
+    字典的 key 可以是 object
+    字典 value 必须是数组,数组元素必须是字典,哪怕数组只有一个元素。
+    参考文件: readme.md -> publish 消息
+    参考官网文档: https://open.iot.10086.cn/doc/v5/develop/detail/251
+    '''
+    @staticmethod
+    def payload_format(ds_id, dictionaries: dict):
+        message = {
+            "id": int(ds_id),
+            "dp": dictionaries
+        }
+        message = bytes("{}".format(message), 'ascii')
+        print(message)
+        return message
+    
+    def client_init(self):
+        self.client = mqtt.Client(self.device_name, protocol=mqtt.MQTTv311)
+        self.client.on_connect = self.on_connect
+        self.client.on_publish = self.on_publish
+        self.client.on_message = self.on_message
+        self.client.connect(self.broker_addr, self.broker_port, keepalive=300)
+        self.client.username_pw_set(self.product_id, self.password)
+        self.client.loop_start()
+
+    @staticmethod
+    def on_connect(client, userdata, flags, rc):
+        print("connet result:" + mqtt.connack_string(rc))
+
+
+    @staticmethod
+    def on_message(client, userdata, msg):
+        print("on_message:", str(msg.payload, 'utf-8'))
+    
+    #当消息已经被发送给中间人,on_publish()回调将会被触发
+    @staticmethod
+    def on_publish(client, userdata, mid):
+        print("on_publish: ", str(mid))
+
+if __name__ == '__main__':
+    MqttOneNet(DEV_NAME)

+ 19 - 0
python38/OneNet_token.py → python38/mylib.py

@@ -1,3 +1,4 @@
+import random
 import base64
 import hmac
 import time
@@ -34,6 +35,24 @@ def cal_token(id, access_key):  # 官方文档给出的核心秘钥计算算法
         version, res, et, method, sign)
     return token
 
+'''
+publish 时,OneNet 对 payload 数据的格式要求:
+ dictionaries 必须为字典
+ 字典的 key 可以是 object
+ 字典 value 必须是数组,数组元素必须是字典,哪怕数组只有一个元素。
+ 参考文件: readme.md -> publish 消息
+参考官网文档: https://open.iot.10086.cn/doc/v5/develop/detail/251
+'''
+def payload_data(ds_id, dictionaries: dict):
+    message = {
+        "id": int(ds_id),
+        "dp": dictionaries
+    }
+    message = bytes("{}".format(message), 'ascii')
+    print(message)
+    return message
+
+
 if __name__ == '__main__':
     PRO_ID = "522417" #产品ID
     accesskey = "dgEP7iOL2/1kVNc1ykDvIhXSVqhb0tLnKinjU2RYpDs="  # 设备秘钥

+ 797 - 0
python38/pyboard.py

@@ -0,0 +1,797 @@
+#!/usr/bin/env python
+#
+# This file is part of the MicroPython project, http://micropython.org/
+#
+# The MIT License (MIT)
+#
+# Copyright (c) 2014-2021 Damien P. George
+# Copyright (c) 2017 Paul Sokolovsky
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+"""
+pyboard interface
+
+This module provides the Pyboard class, used to communicate with and
+control a MicroPython device over a communication channel. Both real
+boards and emulated devices (e.g. running in QEMU) are supported.
+Various communication channels are supported, including a serial
+connection, telnet-style network connection, external process
+connection.
+
+Example usage:
+
+    import pyboard
+    pyb = pyboard.Pyboard('/dev/ttyACM0')
+
+Or:
+
+    pyb = pyboard.Pyboard('192.168.1.1')
+
+Then:
+
+    pyb.enter_raw_repl()
+    pyb.exec('import pyb')
+    pyb.exec('pyb.LED(1).on()')
+    pyb.exit_raw_repl()
+
+Note: if using Python2 then pyb.exec must be written as pyb.exec_.
+To run a script from the local machine on the board and print out the results:
+
+    import pyboard
+    pyboard.execfile('test.py', device='/dev/ttyACM0')
+
+This script can also be run directly.  To execute a local script, use:
+
+    ./pyboard.py test.py
+
+Or:
+
+    python pyboard.py test.py
+
+"""
+
+import sys
+import time
+import os
+import ast
+
+try:
+    stdout = sys.stdout.buffer
+except AttributeError:
+    # Python2 doesn't have buffer attr
+    stdout = sys.stdout
+
+
+def stdout_write_bytes(b):
+    b = b.replace(b"\x04", b"")
+    stdout.write(b)
+    stdout.flush()
+
+
+class PyboardError(Exception):
+    pass
+
+
+class TelnetToSerial:
+    def __init__(self, ip, user, password, read_timeout=None):
+        self.tn = None
+        import telnetlib
+
+        self.tn = telnetlib.Telnet(ip, timeout=15)
+        self.read_timeout = read_timeout
+        if b"Login as:" in self.tn.read_until(b"Login as:", timeout=read_timeout):
+            self.tn.write(bytes(user, "ascii") + b"\r\n")
+
+            if b"Password:" in self.tn.read_until(b"Password:", timeout=read_timeout):
+                # needed because of internal implementation details of the telnet server
+                time.sleep(0.2)
+                self.tn.write(bytes(password, "ascii") + b"\r\n")
+
+                if b"for more information." in self.tn.read_until(
+                    b'Type "help()" for more information.', timeout=read_timeout
+                ):
+                    # login successful
+                    from collections import deque
+
+                    self.fifo = deque()
+                    return
+
+        raise PyboardError("Failed to establish a telnet connection with the board")
+
+    def __del__(self):
+        self.close()
+
+    def close(self):
+        if self.tn:
+            self.tn.close()
+
+    def read(self, size=1):
+        while len(self.fifo) < size:
+            timeout_count = 0
+            data = self.tn.read_eager()
+            if len(data):
+                self.fifo.extend(data)
+                timeout_count = 0
+            else:
+                time.sleep(0.25)
+                if self.read_timeout is not None and timeout_count > 4 * self.read_timeout:
+                    break
+                timeout_count += 1
+
+        data = b""
+        while len(data) < size and len(self.fifo) > 0:
+            data += bytes([self.fifo.popleft()])
+        return data
+
+    def write(self, data):
+        self.tn.write(data)
+        return len(data)
+
+    def inWaiting(self):
+        n_waiting = len(self.fifo)
+        if not n_waiting:
+            data = self.tn.read_eager()
+            self.fifo.extend(data)
+            return len(data)
+        else:
+            return n_waiting
+
+
+class ProcessToSerial:
+    "Execute a process and emulate serial connection using its stdin/stdout."
+
+    def __init__(self, cmd):
+        import subprocess
+
+        self.subp = subprocess.Popen(
+            cmd,
+            bufsize=0,
+            shell=True,
+            preexec_fn=os.setsid,
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+        )
+
+        # Initially was implemented with selectors, but that adds Python3
+        # dependency. However, there can be race conditions communicating
+        # with a particular child process (like QEMU), and selectors may
+        # still work better in that case, so left inplace for now.
+        #
+        # import selectors
+        # self.sel = selectors.DefaultSelector()
+        # self.sel.register(self.subp.stdout, selectors.EVENT_READ)
+
+        import select
+
+        self.poll = select.poll()
+        self.poll.register(self.subp.stdout.fileno())
+
+    def close(self):
+        import signal
+
+        os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM)
+
+    def read(self, size=1):
+        data = b""
+        while len(data) < size:
+            data += self.subp.stdout.read(size - len(data))
+        return data
+
+    def write(self, data):
+        self.subp.stdin.write(data)
+        return len(data)
+
+    def inWaiting(self):
+        # res = self.sel.select(0)
+        res = self.poll.poll(0)
+        if res:
+            return 1
+        return 0
+
+
+class ProcessPtyToTerminal:
+    """Execute a process which creates a PTY and prints slave PTY as
+    first line of its output, and emulate serial connection using
+    this PTY."""
+
+    def __init__(self, cmd):
+        import subprocess
+        import re
+        import serial
+
+        self.subp = subprocess.Popen(
+            cmd.split(),
+            bufsize=0,
+            shell=False,
+            preexec_fn=os.setsid,
+            stdin=subprocess.PIPE,
+            stdout=subprocess.PIPE,
+            stderr=subprocess.PIPE,
+        )
+        pty_line = self.subp.stderr.readline().decode("utf-8")
+        m = re.search(r"/dev/pts/[0-9]+", pty_line)
+        if not m:
+            print("Error: unable to find PTY device in startup line:", pty_line)
+            self.close()
+            sys.exit(1)
+        pty = m.group()
+        # rtscts, dsrdtr params are to workaround pyserial bug:
+        # http://stackoverflow.com/questions/34831131/pyserial-does-not-play-well-with-virtual-port
+        self.ser = serial.Serial(pty, interCharTimeout=1, rtscts=True, dsrdtr=True)
+
+    def close(self):
+        import signal
+
+        os.killpg(os.getpgid(self.subp.pid), signal.SIGTERM)
+
+    def read(self, size=1):
+        return self.ser.read(size)
+
+    def write(self, data):
+        return self.ser.write(data)
+
+    def inWaiting(self):
+        return self.ser.inWaiting()
+
+
+class Pyboard:
+    def __init__(
+        self, device, baudrate=115200, user="micro", password="python", wait=0, exclusive=True
+    ):
+        self.in_raw_repl = False
+        self.use_raw_paste = True
+        if device.startswith("exec:"):
+            self.serial = ProcessToSerial(device[len("exec:") :])
+        elif device.startswith("execpty:"):
+            self.serial = ProcessPtyToTerminal(device[len("qemupty:") :])
+        elif device and device[0].isdigit() and device[-1].isdigit() and device.count(".") == 3:
+            # device looks like an IP address
+            self.serial = TelnetToSerial(device, user, password, read_timeout=10)
+        else:
+            import serial
+
+            # Set options, and exclusive if pyserial supports it
+            serial_kwargs = {"baudrate": baudrate, "interCharTimeout": 1}
+            if serial.__version__ >= "3.3":
+                serial_kwargs["exclusive"] = exclusive
+
+            delayed = False
+            for attempt in range(wait + 1):
+                try:
+                    self.serial = serial.Serial(device, **serial_kwargs)
+                    break
+                except (OSError, IOError):  # Py2 and Py3 have different errors
+                    if wait == 0:
+                        continue
+                    if attempt == 0:
+                        sys.stdout.write("Waiting {} seconds for pyboard ".format(wait))
+                        delayed = True
+                time.sleep(1)
+                sys.stdout.write(".")
+                sys.stdout.flush()
+            else:
+                if delayed:
+                    print("")
+                raise PyboardError("failed to access " + device)
+            if delayed:
+                print("")
+
+    def close(self):
+        self.serial.close()
+
+    def read_until(self, min_num_bytes, ending, timeout=10, data_consumer=None):
+        # if data_consumer is used then data is not accumulated and the ending must be 1 byte long
+        assert data_consumer is None or len(ending) == 1
+
+        data = self.serial.read(min_num_bytes)
+        if data_consumer:
+            data_consumer(data)
+        timeout_count = 0
+        while True:
+            if data.endswith(ending):
+                break
+            elif self.serial.inWaiting() > 0:
+                new_data = self.serial.read(1)
+                if data_consumer:
+                    data_consumer(new_data)
+                    data = new_data
+                else:
+                    data = data + new_data
+                timeout_count = 0
+            else:
+                timeout_count += 1
+                if timeout is not None and timeout_count >= 100 * timeout:
+                    break
+                time.sleep(0.01)
+        return data
+
+    def enter_raw_repl(self, soft_reset=True):
+        self.serial.write(b"\r\x03\x03")  # ctrl-C twice: interrupt any running program
+
+        # flush input (without relying on serial.flushInput())
+        n = self.serial.inWaiting()
+        while n > 0:
+            self.serial.read(n)
+            n = self.serial.inWaiting()
+
+        self.serial.write(b"\r\x01")  # ctrl-A: enter raw REPL
+
+        if soft_reset:
+            data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n>")
+            if not data.endswith(b"raw REPL; CTRL-B to exit\r\n>"):
+                print(data)
+                raise PyboardError("could not enter raw repl")
+
+            self.serial.write(b"\x04")  # ctrl-D: soft reset
+
+            # Waiting for "soft reboot" independently to "raw REPL" (done below)
+            # allows boot.py to print, which will show up after "soft reboot"
+            # and before "raw REPL".
+            data = self.read_until(1, b"soft reboot\r\n")
+            if not data.endswith(b"soft reboot\r\n"):
+                print(data)
+                raise PyboardError("could not enter raw repl")
+
+        data = self.read_until(1, b"raw REPL; CTRL-B to exit\r\n")
+        if not data.endswith(b"raw REPL; CTRL-B to exit\r\n"):
+            print(data)
+            raise PyboardError("could not enter raw repl")
+
+        self.in_raw_repl = True
+
+    def exit_raw_repl(self):
+        self.serial.write(b"\r\x02")  # ctrl-B: enter friendly REPL
+        self.in_raw_repl = False
+
+    def follow(self, timeout, data_consumer=None):
+        # wait for normal output
+        data = self.read_until(1, b"\x04", timeout=timeout, data_consumer=data_consumer)
+        if not data.endswith(b"\x04"):
+            raise PyboardError("timeout waiting for first EOF reception")
+        data = data[:-1]
+
+        # wait for error output
+        data_err = self.read_until(1, b"\x04", timeout=timeout)
+        if not data_err.endswith(b"\x04"):
+            raise PyboardError("timeout waiting for second EOF reception")
+        data_err = data_err[:-1]
+
+        # return normal and error output
+        return data, data_err
+
+    def raw_paste_write(self, command_bytes):
+        # Read initial header, with window size.
+        data = self.serial.read(2)
+        window_size = data[0] | data[1] << 8
+        window_remain = window_size
+
+        # Write out the command_bytes data.
+        i = 0
+        while i < len(command_bytes):
+            while window_remain == 0 or self.serial.inWaiting():
+                data = self.serial.read(1)
+                if data == b"\x01":
+                    # Device indicated that a new window of data can be sent.
+                    window_remain += window_size
+                elif data == b"\x04":
+                    # Device indicated abrupt end.  Acknowledge it and finish.
+                    self.serial.write(b"\x04")
+                    return
+                else:
+                    # Unexpected data from device.
+                    raise PyboardError("unexpected read during raw paste: {}".format(data))
+            # Send out as much data as possible that fits within the allowed window.
+            b = command_bytes[i : min(i + window_remain, len(command_bytes))]
+            self.serial.write(b)
+            window_remain -= len(b)
+            i += len(b)
+
+        # Indicate end of data.
+        self.serial.write(b"\x04")
+
+        # Wait for device to acknowledge end of data.
+        data = self.read_until(1, b"\x04")
+        if not data.endswith(b"\x04"):
+            raise PyboardError("could not complete raw paste: {}".format(data))
+
+    def exec_raw_no_follow(self, command):
+        if isinstance(command, bytes):
+            command_bytes = command
+        else:
+            command_bytes = bytes(command, encoding="utf8")
+
+        # check we have a prompt
+        data = self.read_until(1, b">")
+        if not data.endswith(b">"):
+            raise PyboardError("could not enter raw repl")
+
+        if self.use_raw_paste:
+            # Try to enter raw-paste mode.
+            self.serial.write(b"\x05A\x01")
+            data = self.serial.read(2)
+            if data == b"R\x00":
+                # Device understood raw-paste command but doesn't support it.
+                pass
+            elif data == b"R\x01":
+                # Device supports raw-paste mode, write out the command using this mode.
+                return self.raw_paste_write(command_bytes)
+            else:
+                # Device doesn't support raw-paste, fall back to normal raw REPL.
+                data = self.read_until(1, b"w REPL; CTRL-B to exit\r\n>")
+                if not data.endswith(b"w REPL; CTRL-B to exit\r\n>"):
+                    print(data)
+                    raise PyboardError("could not enter raw repl")
+            # Don't try to use raw-paste mode again for this connection.
+            self.use_raw_paste = False
+
+        # Write command using standard raw REPL, 256 bytes every 10ms.
+        for i in range(0, len(command_bytes), 256):
+            self.serial.write(command_bytes[i : min(i + 256, len(command_bytes))])
+            time.sleep(0.01)
+        self.serial.write(b"\x04")
+
+        # check if we could exec command
+        data = self.serial.read(2)
+        if data != b"OK":
+            raise PyboardError("could not exec command (response: %r)" % data)
+
+    def exec_raw(self, command, timeout=10, data_consumer=None):
+        self.exec_raw_no_follow(command)
+        return self.follow(timeout, data_consumer)
+
+    def eval(self, expression):
+        ret = self.exec_("print({})".format(expression))
+        ret = ret.strip()
+        return ret
+
+    def exec_(self, command, data_consumer=None):
+        ret, ret_err = self.exec_raw(command, data_consumer=data_consumer)
+        if ret_err:
+            raise PyboardError("exception", ret, ret_err)
+        return ret
+
+    def execfile(self, filename):
+        with open(filename, "rb") as f:
+            pyfile = f.read()
+        return self.exec_(pyfile)
+
+    def get_time(self):
+        t = str(self.eval("pyb.RTC().datetime()"), encoding="utf8")[1:-1].split(", ")
+        return int(t[4]) * 3600 + int(t[5]) * 60 + int(t[6])
+
+    def fs_ls(self, src):
+        cmd = (
+            "import uos\nfor f in uos.ilistdir(%s):\n"
+            " print('{:12} {}{}'.format(f[3]if len(f)>3 else 0,f[0],'/'if f[1]&0x4000 else ''))"
+            % (("'%s'" % src) if src else "")
+        )
+        self.exec_(cmd, data_consumer=stdout_write_bytes)
+
+    def fs_cat(self, src, chunk_size=256):
+        cmd = (
+            "with open('%s') as f:\n while 1:\n"
+            "  b=f.read(%u)\n  if not b:break\n  print(b,end='')" % (src, chunk_size)
+        )
+        self.exec_(cmd, data_consumer=stdout_write_bytes)
+
+    def fs_get(self, src, dest, chunk_size=256, progress_callback=None):
+        if progress_callback:
+            src_size = int(self.exec_("import os\nprint(os.stat('%s')[6])" % src))
+            written = 0
+        self.exec_("f=open('%s','rb')\nr=f.read" % src)
+        with open(dest, "wb") as f:
+            while True:
+                data = bytearray()
+                self.exec_("print(r(%u))" % chunk_size, data_consumer=lambda d: data.extend(d))
+                assert data.endswith(b"\r\n\x04")
+                try:
+                    data = ast.literal_eval(str(data[:-3], "ascii"))
+                    if not isinstance(data, bytes):
+                        raise ValueError("Not bytes")
+                except (UnicodeError, ValueError) as e:
+                    raise PyboardError("fs_get: Could not interpret received data: %s" % str(e))
+                if not data:
+                    break
+                f.write(data)
+                if progress_callback:
+                    written += len(data)
+                    progress_callback(written, src_size)
+        self.exec_("f.close()")
+
+    def fs_put(self, src, dest, chunk_size=256, progress_callback=None):
+        if progress_callback:
+            src_size = os.path.getsize(src)
+            written = 0
+        self.exec_("f=open('%s','wb')\nw=f.write" % dest)
+        with open(src, "rb") as f:
+            while True:
+                data = f.read(chunk_size)
+                if not data:
+                    break
+                if sys.version_info < (3,):
+                    self.exec_("w(b" + repr(data) + ")")
+                else:
+                    self.exec_("w(" + repr(data) + ")")
+                if progress_callback:
+                    written += len(data)
+                    progress_callback(written, src_size)
+        self.exec_("f.close()")
+
+    def fs_mkdir(self, dir):
+        self.exec_("import uos\nuos.mkdir('%s')" % dir)
+
+    def fs_rmdir(self, dir):
+        self.exec_("import uos\nuos.rmdir('%s')" % dir)
+
+    def fs_rm(self, src):
+        self.exec_("import uos\nuos.remove('%s')" % src)
+
+
+# in Python2 exec is a keyword so one must use "exec_"
+# but for Python3 we want to provide the nicer version "exec"
+setattr(Pyboard, "exec", Pyboard.exec_)
+
+
+def execfile(filename, device="/dev/ttyACM0", baudrate=115200, user="micro", password="python"):
+    pyb = Pyboard(device, baudrate, user, password)
+    pyb.enter_raw_repl()
+    output = pyb.execfile(filename)
+    stdout_write_bytes(output)
+    pyb.exit_raw_repl()
+    pyb.close()
+
+
+def filesystem_command(pyb, args, progress_callback=None):
+    def fname_remote(src):
+        if src.startswith(":"):
+            src = src[1:]
+        return src
+
+    def fname_cp_dest(src, dest):
+        src = src.rsplit("/", 1)[-1]
+        if dest is None or dest == "":
+            dest = src
+        elif dest == ".":
+            dest = "./" + src
+        elif dest.endswith("/"):
+            dest += src
+        return dest
+
+    cmd = args[0]
+    args = args[1:]
+    try:
+        if cmd == "cp":
+            srcs = args[:-1]
+            dest = args[-1]
+            if srcs[0].startswith("./") or dest.startswith(":"):
+                op = pyb.fs_put
+                fmt = "cp %s :%s"
+                dest = fname_remote(dest)
+            else:
+                op = pyb.fs_get
+                fmt = "cp :%s %s"
+            for src in srcs:
+                src = fname_remote(src)
+                dest2 = fname_cp_dest(src, dest)
+                print(fmt % (src, dest2))
+                op(src, dest2, progress_callback=progress_callback)
+        else:
+            op = {
+                "ls": pyb.fs_ls,
+                "cat": pyb.fs_cat,
+                "mkdir": pyb.fs_mkdir,
+                "rmdir": pyb.fs_rmdir,
+                "rm": pyb.fs_rm,
+            }[cmd]
+            if cmd == "ls" and not args:
+                args = [""]
+            for src in args:
+                src = fname_remote(src)
+                print("%s :%s" % (cmd, src))
+                op(src)
+    except PyboardError as er:
+        print(str(er.args[2], "ascii"))
+        pyb.exit_raw_repl()
+        pyb.close()
+        sys.exit(1)
+
+
+_injected_import_hook_code = """\
+import uos, uio
+class _FS:
+  class File(uio.IOBase):
+    def __init__(self):
+      self.off = 0
+    def ioctl(self, request, arg):
+      return 0
+    def readinto(self, buf):
+      buf[:] = memoryview(_injected_buf)[self.off:self.off + len(buf)]
+      self.off += len(buf)
+      return len(buf)
+  mount = umount = chdir = lambda *args: None
+  def stat(self, path):
+    if path == '_injected.mpy':
+      return tuple(0 for _ in range(10))
+    else:
+      raise OSError(-2) # ENOENT
+  def open(self, path, mode):
+    return self.File()
+uos.mount(_FS(), '/_')
+uos.chdir('/_')
+from _injected import *
+uos.umount('/_')
+del _injected_buf, _FS
+"""
+
+
+def main():
+    import argparse
+
+    cmd_parser = argparse.ArgumentParser(description="Run scripts on the pyboard.")
+    cmd_parser.add_argument(
+        "-d",
+        "--device",
+        default=os.environ.get("PYBOARD_DEVICE", "/dev/ttyACM0"),
+        help="the serial device or the IP address of the pyboard",
+    )
+    cmd_parser.add_argument(
+        "-b",
+        "--baudrate",
+        default=os.environ.get("PYBOARD_BAUDRATE", "115200"),
+        help="the baud rate of the serial device",
+    )
+    cmd_parser.add_argument("-u", "--user", default="micro", help="the telnet login username")
+    cmd_parser.add_argument("-p", "--password", default="python", help="the telnet login password")
+    cmd_parser.add_argument("-c", "--command", help="program passed in as string")
+    cmd_parser.add_argument(
+        "-w",
+        "--wait",
+        default=0,
+        type=int,
+        help="seconds to wait for USB connected board to become available",
+    )
+    group = cmd_parser.add_mutually_exclusive_group()
+    group.add_argument(
+        "--soft-reset",
+        default=True,
+        action="store_true",
+        help="Whether to perform a soft reset when connecting to the board [default]",
+    )
+    group.add_argument(
+        "--no-soft-reset",
+        action="store_false",
+        dest="soft_reset",
+    )
+    group = cmd_parser.add_mutually_exclusive_group()
+    group.add_argument(
+        "--follow",
+        action="store_true",
+        default=None,
+        help="follow the output after running the scripts [default if no scripts given]",
+    )
+    group.add_argument(
+        "--no-follow",
+        action="store_false",
+        dest="follow",
+    )
+    group = cmd_parser.add_mutually_exclusive_group()
+    group.add_argument(
+        "--exclusive",
+        action="store_true",
+        default=True,
+        help="Open the serial device for exclusive access [default]",
+    )
+    group.add_argument(
+        "--no-exclusive",
+        action="store_false",
+        dest="exclusive",
+    )
+    cmd_parser.add_argument(
+        "-f",
+        "--filesystem",
+        action="store_true",
+        help="perform a filesystem action: "
+        "cp local :device | cp :device local | cat path | ls [path] | rm path | mkdir path | rmdir path",
+    )
+    cmd_parser.add_argument("files", nargs="*", help="input files")
+    args = cmd_parser.parse_args()
+
+    # open the connection to the pyboard
+    try:
+        pyb = Pyboard(
+            args.device, args.baudrate, args.user, args.password, args.wait, args.exclusive
+        )
+    except PyboardError as er:
+        print(er)
+        sys.exit(1)
+
+    # run any command or file(s)
+    if args.command is not None or args.filesystem or len(args.files):
+        # we must enter raw-REPL mode to execute commands
+        # this will do a soft-reset of the board
+        try:
+            pyb.enter_raw_repl(args.soft_reset)
+        except PyboardError as er:
+            print(er)
+            pyb.close()
+            sys.exit(1)
+
+        def execbuffer(buf):
+            try:
+                if args.follow is None or args.follow:
+                    ret, ret_err = pyb.exec_raw(
+                        buf, timeout=None, data_consumer=stdout_write_bytes
+                    )
+                else:
+                    pyb.exec_raw_no_follow(buf)
+                    ret_err = None
+            except PyboardError as er:
+                print(er)
+                pyb.close()
+                sys.exit(1)
+            except KeyboardInterrupt:
+                sys.exit(1)
+            if ret_err:
+                pyb.exit_raw_repl()
+                pyb.close()
+                stdout_write_bytes(ret_err)
+                sys.exit(1)
+
+        # do filesystem commands, if given
+        if args.filesystem:
+            filesystem_command(pyb, args.files)
+            del args.files[:]
+
+        # run the command, if given
+        if args.command is not None:
+            execbuffer(args.command.encode("utf-8"))
+
+        # run any files
+        for filename in args.files:
+            with open(filename, "rb") as f:
+                pyfile = f.read()
+                if filename.endswith(".mpy") and pyfile[0] == ord("M"):
+                    pyb.exec_("_injected_buf=" + repr(pyfile))
+                    pyfile = _injected_import_hook_code
+                execbuffer(pyfile)
+
+        # exiting raw-REPL just drops to friendly-REPL mode
+        pyb.exit_raw_repl()
+
+    # if asked explicitly, or no files given, then follow the output
+    if args.follow or (args.command is None and not args.filesystem and len(args.files) == 0):
+        try:
+            ret, ret_err = pyb.follow(timeout=None, data_consumer=stdout_write_bytes)
+        except PyboardError as er:
+            print(er)
+            sys.exit(1)
+        except KeyboardInterrupt:
+            sys.exit(1)
+        if ret_err:
+            pyb.close()
+            stdout_write_bytes(ret_err)
+            sys.exit(1)
+
+    # close the connection to the pyboard
+    pyb.close()
+
+
+if __name__ == "__main__":
+    main()

+ 34 - 0
python38/test.py

@@ -0,0 +1,34 @@
+
+class Test():
+    def __init__(self) -> None:
+        print("Test() init")
+        self.ok = 1
+    
+    def upload_data(self):
+        print("upload")
+        self.ok += 1
+    
+test_ob = Test()
+dat = {
+  'id': 1, 
+  'dp':{
+    'system': [{
+        'v': {
+            'GPS': "96'209'',69'148''", 
+            'power': 34, 
+            'altitude': 5651
+            }
+        }], 
+        'sensor': [{
+            'v': {
+                'humidity': 5725, 
+                'temperature': 10674
+                }
+            }]
+  }
+  }
+
+# tim = Timer(-1)
+# tim.init(period=1000, mode=Timer.ONE_SHOT, callback=lambda t:print(1))
+# tim.init(period=2000, mode=Timer.PERIODIC, callback=lambda t:print(2))
+# print()

+ 3 - 0
python38/test2.py

@@ -0,0 +1,3 @@
+from test import test_ob
+
+print("ok")

+ 0 - 4
test.py

@@ -1,4 +0,0 @@
-import mywifi
-
-print('network config:', mywifi.wlan.ifconfig())
-