You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
13 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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波特率
* 参数3data bits 5~8
* 参数4Parity 0NONE 1EVEN 2ODD
* 参数5stop bits 1~2
* 参数6flow control 0: FC_NONE 1FC_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)