RIceWqy 2 years ago
commit aa6d67f879

@ -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波特率
* 参数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)
Loading…
Cancel
Save