commit aa6d67f8795d058ce779594eeb2deb4bb874e7cc Author: RIceWqy <1840169763@qq.com> Date: Sun Feb 25 21:35:32 2024 +0800 init diff --git a/main.py b/main.py new file mode 100644 index 0000000..776f184 --- /dev/null +++ b/main.py @@ -0,0 +1,482 @@ +import log +import usocket as socket +import ubinascii as binascii +import urandom as random +import log +import ure as re +import ustruct as struct +import urandom as random +import _thread +import utime +import checkNet +import ujson +import utime +from uio import StringIO +""" +运行本例程,需要通过串口线连接开发板的 MAIN 口和PC,在PC上通过串口工具 +打开 MAIN 口,并向该端口发送数据,即可看到 PC 发送过来的消息。 +""" +from machine import UART + +''' + * 参数1:端口 + 注:EC100YCN平台与EC600SCN平台,UARTn作用如下 + UART0 - DEBUG PORT + UART1 – BT PORT + UART2 – MAIN PORT + UART3 – USB CDC PORT + * 参数2:波特率 + * 参数3:data bits (5~8) + * 参数4:Parity (0:NONE 1:EVEN 2:ODD) + * 参数5:stop bits (1~2) + * 参数6:flow control (0: FC_NONE 1:FC_HW) +''' +from ucollections import namedtuple + + + +REG_REQUEST = { + "jsonrpc": "2.0", + "id": "1", + "method":"/iotserver/device/reg", + "params":{ + "secret_key":"ELXPMM12bxE0LQ6YtWr9u7tyZZSMWALKAIiLdDlwUai5SBUS", + "serial_number":"SN_TEST_REAL_001" + } +} + +GRAVITY = 9.8 + +LOGGER = log.getLogger(__name__) + +# Opcodes +OP_CONT = 0x0 +OP_TEXT = 0x1 +OP_BYTES = 0x2 +OP_CLOSE = 0x8 +OP_PING = 0x9 +OP_PONG = 0xa + +# Close codes +CLOSE_OK = 1000 +CLOSE_GOING_AWAY = 1001 +CLOSE_PROTOCOL_ERROR = 1002 +CLOSE_DATA_NOT_SUPPORTED = 1003 +CLOSE_BAD_DATA = 1007 +CLOSE_POLICY_VIOLATION = 1008 +CLOSE_TOO_BIG = 1009 +CLOSE_MISSING_EXTN = 1010 +CLOSE_BAD_CONDITION = 1011 + +URL_RE = re.compile(r'(wss|ws)://([A-Za-z0-9-\.]+)(?:\:([0-9]+))?(/.+)?') +URI = namedtuple('URI', ('protocol', 'hostname', 'port', 'path')) + + +def urlparse(uri): + """Parse ws:// URLs""" + match = URL_RE.match(uri) + if match: + protocol = match.group(1) + host = match.group(2) + port = match.group(3) + path = match.group(4) + + if protocol == 'wss': + if port is None: + port = 443 + elif protocol == 'ws': + if port is None: + port = 80 + else: + raise ValueError('Scheme {} is invalid'.format(protocol)) + + return URI(protocol, host, int(port), path) + + +class NoDataException(Exception): + pass + + +class ConnectionClosed(Exception): + pass + + +class Websocket(object): + """ + Basis of the Websocket protocol. + + This can probably be replaced with the C-based websocket module, but + this one currently supports more options. + """ + is_client = False + + def __init__(self, sock, debug=False): + self.sock = sock + self.open = True + self.debug = debug + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + self.close() + + def settimeout(self, timeout): + self.sock.settimeout(timeout) + + def read_frame(self, max_size=None): + """ + Read a frame from the socket. + See https://tools.ietf.org/html/rfc6455#section-5.2 for the details. + """ + + # Frame header + two_bytes = self.sock.read(2) + + if not two_bytes: + raise NoDataException + + byte1, byte2 = struct.unpack('!BB', two_bytes) + + # Byte 1: FIN(1) _(1) _(1) _(1) OPCODE(4) + fin = bool(byte1 & 0x80) + opcode = byte1 & 0x0f + + # Byte 2: MASK(1) LENGTH(7) + mask = bool(byte2 & (1 << 7)) + length = byte2 & 0x7f + + if length == 126: # Magic number, length header is 2 bytes + length, = struct.unpack('!H', self.sock.read(2)) + elif length == 127: # Magic number, length header is 8 bytes + length, = struct.unpack('!Q', self.sock.read(8)) + + if mask: # Mask is 4 bytes + mask_bits = self.sock.read(4) + + try: + data = self.sock.read(length) + except MemoryError: + # We can't receive this many bytes, close the socket + if self.debug: LOGGER.info("Frame of length %s too big. Closing", length) + self.close(code=CLOSE_TOO_BIG) + return True, OP_CLOSE, None + + if mask: + data = bytes(b ^ mask_bits[i % 4] + for i, b in enumerate(data)) + + return fin, opcode, data + + def write_frame(self, opcode, data=b''): + """ + Write a frame to the socket. + See https://tools.ietf.org/html/rfc6455#section-5.2 for the details. + """ + fin = True + mask = self.is_client # messages sent by client are masked + + length = len(data) + + # Frame header + # Byte 1: FIN(1) _(1) _(1) _(1) OPCODE(4) + byte1 = 0x80 if fin else 0 + byte1 |= opcode + + # Byte 2: MASK(1) LENGTH(7) + byte2 = 0x80 if mask else 0 + + if length < 126: # 126 is magic value to use 2-byte length header + byte2 |= length + self.sock.write(struct.pack('!BB', byte1, byte2)) + + elif length < (1 << 16): # Length fits in 2-bytes + byte2 |= 126 # Magic code + self.sock.write(struct.pack('!BBH', byte1, byte2, length)) + + elif length < (1 << 64): + byte2 |= 127 # Magic code + self.sock.write(struct.pack('!BBQ', byte1, byte2, length)) + + else: + raise ValueError() + + if mask: # Mask is 4 bytes + mask_bits = struct.pack('!I', random.getrandbits(32)) + self.sock.write(mask_bits) + + data = bytes(b ^ mask_bits[i % 4] + for i, b in enumerate(data)) + + self.sock.write(data) + + def recv(self): + """ + Receive data from the websocket. + + This is slightly different from 'websockets' in that it doesn't + fire off a routine to process frames and put the data in a queue. + If you don't call recv() sufficiently often you won't process control + frames. + """ + assert self.open + + while self.open: + try: + fin, opcode, data = self.read_frame() + except NoDataException: + return '' + except ValueError: + if self.debug: LOGGER.info("Failed to read frame. Socket dead.") + self._close() + raise ConnectionClosed() + + if not fin: + raise NotImplementedError() + + if opcode == OP_TEXT: + return data.decode('utf-8') + elif opcode == OP_BYTES: + return data + elif opcode == OP_CLOSE: + self._close() + return + elif opcode == OP_PONG: + # Ignore this frame, keep waiting for a data frame + continue + elif opcode == OP_PING: + # We need to send a pong frame + if self.debug: LOGGER.info("Sending PONG") + self.write_frame(OP_PONG, data) + # And then wait to receive + continue + elif opcode == OP_CONT: + # This is a continuation of a previous frame + raise NotImplementedError(opcode) + else: + raise ValueError(opcode) + + def send(self, buf): + """Send data to the websocket.""" + + assert self.open + + if isinstance(buf, str): + opcode = OP_TEXT + buf = buf.encode('utf-8') + elif isinstance(buf, bytes): + opcode = OP_BYTES + else: + raise TypeError() + + self.write_frame(opcode, buf) + + def close(self, code=CLOSE_OK, reason=''): + """Close the websocket.""" + if not self.open: + return + + buf = struct.pack('!H', code) + reason.encode('utf-8') + + self.write_frame(OP_CLOSE, buf) + self._close() + + def _close(self): + if self.debug: LOGGER.info("Connection closed") + self.open = False + self.sock.close() + + +class WebsocketClient(Websocket): + is_client = True + + +class Client(object): + + @staticmethod + def connect(uri, headers=None, debug=False): + """ + Connect a websocket. + :param uri: example ws://172.16.185.123/ + :param headers: k, v of header + :param debug: allow output log + :return: + """ + if not headers: + headers = dict() + if not isinstance(headers, dict): + raise Exception("headers must be dict type but {} you given.".format(type(headers))) + + uri = urlparse(uri) + assert uri + + if debug: LOGGER.info("open connection %s:%s", + uri.hostname, uri.port) + + sock = socket.socket() + addr = socket.getaddrinfo(uri.hostname, uri.port) + + sock.connect(addr[0][4]) + + + + if uri.protocol == 'wss': + import ussl + sock = ussl.wrap_socket(sock) + + def send_header(header, *args): + if debug: LOGGER.info(str(header), *args) + sock.write(header % args + '\r\n') + + # Sec-WebSocket-Key is 16 bytes of random base64 encoded + key = binascii.b2a_base64(bytes(random.getrandbits(8) for _ in range(16)))[:-1] + send_header(b'GET %s HTTP/1.1', uri.path or '/') + send_header(b'Host: %s:%s', uri.hostname, uri.port) + send_header(b'Connection: Upgrade') + send_header(b'Upgrade: websocket') + send_header(b'Sec-WebSocket-Key: %s', key) + send_header(b'Sec-WebSocket-Version: 13') + send_header(b'Origin: http://{hostname}:{port}'.format( + hostname=uri.hostname, + port=uri.port) + ) + for k, v in headers.items(): + send_header('{}:{}'.format(k, v).encode()) + send_header(b'') + + header = sock.readline()[:-2] + assert header.startswith(b'HTTP/1.1 101 '), header + + # We don't (currently) need these headers + # FIXME: should we check the return key? + while header: + if debug: LOGGER.info(str(header)) + header = sock.readline()[:-2] + + return WebsocketClient(sock, debug) + + +def recv(cli): + while True: + # 死循环接收数据 + recv_data = cli.recv() + + print(recv_data) + + if not recv_data: + # 服务器关闭连接或客户端关闭连接 + print("cli close") + cli.close() + break + #io = StringIO() + #ujson.dump("{}".format(recv_data), io) + request = ujson.loads("{}".format(recv_data)) + + if "method" in request: + if request["method"] == "/lampControl/push": + uart_test = Example_uart(bate=9600) + print(request["params"]) + print("{}".format(request["params"])) + uart_test.uartWrite("{}".format(request["params"])) + utime.sleep(2) + print(uart_test.uartRead(1024)) + del uart_test + continue + + if request["method"] == "/lampControl": + uart_test = Example_uart(bate=9600) + print(request["params"]) + print("{}".format(request["params"])) + uart_test.uartWrite("{}".format(request["params"])) + utime.sleep(2) + msg = uart_test.uartRead(1024) + print(msg) + utf8_msg = msg.decode() + + resp = { + "jsonrpc": "2.0", + "id": request["id"], + "result":utf8_msg, + "error":{ + "message":"", + "code":200, + "data":"" + } + } + + + cli.send(ujson.dumps(resp)) + + del uart_test + continue + + if request["method"] == "towgo.websocket.ping": + del request["params"] + del request["method"] + request["error"]={'message':"no",'code':500} + + + json_str = ujson.dumps(request) + cli.send(json_str) + + continue + + + + + + + +# 设置日志输出级别 +log.basicConfig(level=log.INFO) +uart_log = log.getLogger("UART") + +class Example_uart(object): + def __init__(self, no=UART.UART2, bate=115200, data_bits=8, parity=0, stop_bits=1, flow_control=0): + self.uart = UART(no, bate, data_bits, parity, stop_bits, flow_control) + #self.uart.set_callback(self.callback) + + + def callback(self, para): + uart_log.info("call para:{}".format(para)) + if(0 == para[0]): + self.uartRead(para[2]) + + + def uartWrite(self, msg): + uart_log.info("write msg:{}".format(msg)) + self.uart.write(msg) + + def uartRead(self, len): + msg = self.uart.read(len) + utf8_msg = msg.decode() + uart_log.info("UartRead msg: {}".format(utf8_msg)) + return utf8_msg + + def uartWrite_test(self): + for i in range(10): + write_msg = "Hello count={}".format(i) + self.uartWrite(write_msg) + utime.sleep(1) + + + +if __name__ == '__main__': + while True: + stagecode, subcode = checkNet.wait_network_connected(30) + if stagecode == 3 and subcode == 1: + try: + client = Client.connect('wss://iotserver.ruixininfo.com/jsonrpc/websocket', debug=False) + + client.send(ujson.dumps(REG_REQUEST)) + #print(s) + #utime.sleep(2) + + print("发送注册信息成功,开始接收信息") + recv(client) + + except Exception as e: + print(e) + # We can't receive this many bytes, close the socket + + utime.sleep(10) \ No newline at end of file