更新MINI的固件,包括(绘制指针,网络SSL,DS18X20,知心,BLE-NOT)
This commit is contained in:
BIN
boards/HDK/MixGo_MINI-V1.7.pdf
Normal file
BIN
boards/HDK/MixGo_MINI-V1.7.pdf
Normal file
Binary file not shown.
@@ -1,56 +1,52 @@
|
||||
#ADXL345
|
||||
import time
|
||||
import ustruct
|
||||
from micropython import const
|
||||
|
||||
DATA_FORMAT = const(0x31)
|
||||
BW_RATE = const(0x2c)
|
||||
POWER_CTL = const(0x2d)
|
||||
INT_ENABLE = const(0x2E)
|
||||
OFSX = const(0x1e)
|
||||
OFSY = const(0x1f)
|
||||
OFSZ = const(0x20)
|
||||
|
||||
class ADXL345:
|
||||
def __init__(self, i2c, address=0X53):
|
||||
self._device = i2c
|
||||
self._address = address
|
||||
for addr in self._device.scan():
|
||||
if self._device.readfrom_mem(addr, 0, 1)[0] == 0xe5:
|
||||
self._address = addr
|
||||
break
|
||||
else:
|
||||
raise AttributeError("Cannot find a ADXL345")
|
||||
|
||||
self._wreg(DATA_FORMAT,0x2B) #16g量程
|
||||
self._wreg(BW_RATE,0x0A) #数据输出速度为100Hz
|
||||
self._wreg(INT_ENABLE,0x00) #不使用中断
|
||||
|
||||
self._wreg(OFSX,0x00)
|
||||
self._wreg(OFSY,0x00)
|
||||
self._wreg(OFSZ,0x00)
|
||||
self._wreg(POWER_CTL,0x08) #链接使能,测量模式
|
||||
time.sleep(0.5)
|
||||
|
||||
def readXYZ(self):
|
||||
x, = ustruct.unpack('<h', self._rreg(0x32,2))
|
||||
y, = ustruct.unpack('<h', self._rreg(0x34,2))
|
||||
z, = ustruct.unpack('<h', self._rreg(0x36,2))
|
||||
return (x/256,y/256,z/256)
|
||||
|
||||
def readX(self):
|
||||
return self.readXYZ()[0]
|
||||
|
||||
def readY(self):
|
||||
return self.readXYZ()[1]
|
||||
|
||||
def readZ(self):
|
||||
return self.readXYZ()[2]
|
||||
|
||||
def _wreg(self, reg, val):
|
||||
'''Write memory address'''
|
||||
self._device.writeto_mem(self._address,reg,val.to_bytes(1, 'little'))
|
||||
|
||||
def _rreg(self, reg,nbytes=1):
|
||||
'''Read memory address'''
|
||||
return self._device.readfrom_mem(self._address, reg, nbytes)[0] if nbytes<=1 else self._device.readfrom_mem(self._address, reg, nbytes)[0:nbytes]
|
||||
#ADXL345
|
||||
import time
|
||||
import ustruct
|
||||
from micropython import const
|
||||
|
||||
DATA_FORMAT = const(0x31)
|
||||
BW_RATE = const(0x2c)
|
||||
POWER_CTL = const(0x2d)
|
||||
INT_ENABLE = const(0x2E)
|
||||
OFSX = const(0x1e)
|
||||
OFSY = const(0x1f)
|
||||
OFSZ = const(0x20)
|
||||
|
||||
class ADXL345:
|
||||
def __init__(self, i2c, address=0X53):
|
||||
self._device = i2c
|
||||
self._address = address
|
||||
if self._rreg(0x0) != 0xe5:
|
||||
raise AttributeError("Cannot find a ADXL345")
|
||||
|
||||
self._wreg(DATA_FORMAT,0x2B) #16g量程
|
||||
self._wreg(BW_RATE,0x0A) #数据输出速度为100Hz
|
||||
self._wreg(INT_ENABLE,0x00) #不使用中断
|
||||
|
||||
self._wreg(OFSX,0x00)
|
||||
self._wreg(OFSY,0x00)
|
||||
self._wreg(OFSZ,0x00)
|
||||
self._wreg(POWER_CTL,0x08) #链接使能,测量模式
|
||||
time.sleep(0.5)
|
||||
|
||||
def readXYZ(self):
|
||||
x, = ustruct.unpack('<h', self._rreg(0x32,2))
|
||||
y, = ustruct.unpack('<h', self._rreg(0x34,2))
|
||||
z, = ustruct.unpack('<h', self._rreg(0x36,2))
|
||||
return (x/256,y/256,z/256)
|
||||
|
||||
def readX(self):
|
||||
return self.readXYZ()[0]
|
||||
|
||||
def readY(self):
|
||||
return self.readXYZ()[1]
|
||||
|
||||
def readZ(self):
|
||||
return self.readXYZ()[2]
|
||||
|
||||
def _wreg(self, reg, val):
|
||||
'''Write memory address'''
|
||||
self._device.writeto_mem(self._address,reg,val.to_bytes(1, 'little'))
|
||||
|
||||
def _rreg(self, reg,nbytes=1):
|
||||
'''Read memory address'''
|
||||
return self._device.readfrom_mem(self._address, reg, nbytes)[0] if nbytes<=1 else self._device.readfrom_mem(self._address, reg, nbytes)[0:nbytes]
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
"""
|
||||
Bluetooth-HID-Keyboard
|
||||
|
||||
Micropython library for the Bluetooth-HID-Keyboard
|
||||
=======================================================
|
||||
#https://github.com/Heerkog/MicroPythonBLEHID
|
||||
|
||||
@dahanzimin From the Mixly Team
|
||||
"""
|
||||
import bluetooth
|
||||
import struct, time
|
||||
from micropython import const
|
||||
from ubinascii import hexlify
|
||||
from ble_advertising import advertising_payload
|
||||
from bluetooth import UUID, FLAG_READ, FLAG_WRITE ,FLAG_NOTIFY, FLAG_WRITE_NO_RESPONSE
|
||||
|
||||
_IRQ_CENTRAL_CONNECT = const(1)
|
||||
_IRQ_CENTRAL_DISCONNECT = const(2)
|
||||
_IRQ_GATTS_WRITE = const(3)
|
||||
_IRQ_MTU_EXCHANGED = const(21)
|
||||
_IRQ_CONNECTION_UPDATE = const(27)
|
||||
_IRQ_PASSKEY_ACTION = const(31)
|
||||
_PASSKEY_ACTION_INPUT = const(2)
|
||||
_PASSKEY_ACTION_DISP = const(3)
|
||||
_PASSKEY_ACTION_NUMCMP = const(4)
|
||||
|
||||
_HID_INPUT_REPORT = const(b'\x05\x01\t\x06\xa1\x01\x85\x01u\x01\x95\x08\x05\x07\x19\xe0)\xe7\x15\x00%\x01\x81\x02\x95\x01u\x08\x81\x01\x95\x05u\x01\x05\x08\x19\x01)\x05\x91\x02\x95\x01u\x03\x91\x01\x95\x06u\x08\x15\x00%e\x05\x07\x19\x00)e\x81\x00\xc0')
|
||||
_KEYCODE = const(b'\x00\x00\x00\x00\x00\x00\x00\x00*+(\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00)\x00\x00\x00\x00,\x9e\xb4\xa0\xa1\xa2\xa44\xa6\xa7\xa5\xae6-78\'\x1e\x1f !"#$%&\xb33\xb6.\xb7\xb8\x9f\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d/10\xa3\xad5\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\xaf\xb1\xb0\xb5L')
|
||||
|
||||
_DIS = (UUID(0x180A), ( (UUID(0x2A24), FLAG_READ),
|
||||
(UUID(0x2A25), FLAG_READ),
|
||||
(UUID(0x2A26), FLAG_READ),
|
||||
(UUID(0x2A27), FLAG_READ),
|
||||
(UUID(0x2A28), FLAG_READ),
|
||||
(UUID(0x2A29), FLAG_READ),
|
||||
(UUID(0x2A50), FLAG_READ), ), )
|
||||
|
||||
_BAS = (UUID(0x180F), ( (UUID(0x2A19), FLAG_READ | FLAG_NOTIFY, (
|
||||
(UUID(0x2902), 0x01 | 0x02),
|
||||
(UUID(0x2904), 0x01),)), ), )
|
||||
|
||||
_HIDS = (UUID(0x1812), ((UUID(0x2A4A), FLAG_READ),
|
||||
(UUID(0x2A4B), FLAG_READ),
|
||||
(UUID(0x2A4C), FLAG_READ | FLAG_WRITE | FLAG_WRITE_NO_RESPONSE),
|
||||
(UUID(0x2A4D), FLAG_READ | FLAG_NOTIFY, (
|
||||
(UUID(0x2902), 0x01 | 0x02),
|
||||
(UUID(0x2908), 0x01 | 0x02),)),
|
||||
(UUID(0x2A4D), FLAG_READ | FLAG_WRITE, (
|
||||
(UUID(0x2902), 0x01 | 0x02),
|
||||
(UUID(0x2908), 0x01 | 0x02),)),
|
||||
(UUID(0x2A4E), FLAG_READ | FLAG_WRITE | FLAG_WRITE_NO_RESPONSE), ), )
|
||||
|
||||
class Keyboard:
|
||||
def __init__(self, name=None, passkey=1234, battery_level=100):
|
||||
if (name is '') or (name is None):
|
||||
name = "Mixgo_" + self.mac[-6:].upper()
|
||||
print("Keyboard name:", name)
|
||||
|
||||
self._ble = bluetooth.BLE()
|
||||
self._ble.active(True)
|
||||
self._ble.irq(self._irq)
|
||||
self._ble.config(gap_name=name)
|
||||
self._ble.config(mtu=23)
|
||||
self.device_state = False
|
||||
self.conn_handle = None
|
||||
self.passkey = passkey
|
||||
self.battery_level = battery_level
|
||||
self.report = b'\x00'
|
||||
|
||||
handles = self._ble.gatts_register_services((_DIS, _BAS, _HIDS))
|
||||
self._service_characteristics(handles)
|
||||
self._payload = advertising_payload(name=name, services=[UUID(0x1812)], appearance=const(961))
|
||||
self.advertise()
|
||||
|
||||
def _irq(self, event, data):
|
||||
# Interrupt request callback function
|
||||
if event == _IRQ_CENTRAL_CONNECT:
|
||||
self.conn_handle, _, _ = data
|
||||
print("Keyboard connected: ", self.conn_handle)
|
||||
self.device_state = True
|
||||
elif event == _IRQ_CENTRAL_DISCONNECT:
|
||||
self.conn_handle = None
|
||||
conn_handle, addr_type, addr = data
|
||||
print("Keyboard disconnected: ", conn_handle)
|
||||
self.advertise()
|
||||
self.device_state = False
|
||||
elif event == _IRQ_MTU_EXCHANGED:
|
||||
conn_handle, mtu = data
|
||||
self._ble.config(mtu=mtu)
|
||||
print("MTU exchanged: ", mtu)
|
||||
elif event == _IRQ_CONNECTION_UPDATE:
|
||||
self.conn_handle, _, _, _, _ = data
|
||||
print("Connection update")
|
||||
elif event == _IRQ_PASSKEY_ACTION:
|
||||
conn_handle, action, passkey = data
|
||||
print("Passkey action", conn_handle, action, passkey)
|
||||
if action == _PASSKEY_ACTION_NUMCMP:
|
||||
self._ble.gap_passkey(conn_handle, action, False)
|
||||
elif action == _PASSKEY_ACTION_DISP:
|
||||
print("Displaying passkey")
|
||||
self._ble.gap_passkey(conn_handle, action, self.passkey)
|
||||
elif action == _PASSKEY_ACTION_INPUT:
|
||||
print(" Prompting for passkey")
|
||||
self._ble.gap_passkey(conn_handle, action, None)
|
||||
else:
|
||||
print("unknown action")
|
||||
elif event == _IRQ_GATTS_WRITE:
|
||||
conn_handle, attr_handle = data
|
||||
self.report = self._ble.gatts_read(attr_handle)
|
||||
#else:
|
||||
#print("Unhandled IRQ event: ", event, data)
|
||||
|
||||
def _service_characteristics(self, handles):
|
||||
(h_mod, h_ser, h_fwr, h_hwr, h_swr, h_man, h_pnp) = handles[0]
|
||||
(self.h_bat, h_ccc, h_bfmt,) = handles[1]
|
||||
(h_info, h_hid, _, self.h_rep, _, h_d1, _, _, h_d2, h_proto) = handles[2]
|
||||
|
||||
# Write DIS characteristics.
|
||||
self._ble.gatts_write(h_mod, b'1')
|
||||
self._ble.gatts_write(h_ser, b'1')
|
||||
self._ble.gatts_write(h_fwr, b'1')
|
||||
self._ble.gatts_write(h_hwr, b'1')
|
||||
self._ble.gatts_write(h_swr, b'1')
|
||||
self._ble.gatts_write(h_man, b'Homebrew')
|
||||
self._ble.gatts_write(h_pnp, struct.pack("<BHHH", 0x01, 0xFE61, 0x01, 0x0123))
|
||||
# Write BAS characteristics.
|
||||
self._ble.gatts_write(self.h_bat, struct.pack("<B", self.battery_level))
|
||||
self._ble.gatts_write(h_bfmt, b'\x04\x00\xad\x27\x01\x00\x00')
|
||||
self._ble.gatts_write(h_ccc, b'\x00\x00')
|
||||
# Write service characteristics
|
||||
self._ble.gatts_write(h_info, b"\x01\x01\x00\x02")
|
||||
self._ble.gatts_write(h_hid, _HID_INPUT_REPORT)
|
||||
self._ble.gatts_write(h_d1, b'\x01\x01')
|
||||
self._ble.gatts_write(h_d2, b'\x01\x02')
|
||||
self._ble.gatts_write(h_proto, b"\x01")
|
||||
|
||||
def state(self):
|
||||
return int.from_bytes(self.report, 'big')
|
||||
|
||||
def is_connected(self):
|
||||
return self.device_state
|
||||
|
||||
def advertise(self, interval_us=100000):
|
||||
print("Starting advertising")
|
||||
self._ble.gap_advertise(interval_us, adv_data=self._payload)
|
||||
|
||||
def notify_hid(self, special=0, general=0, release=True):
|
||||
if self.is_connected():
|
||||
_keys = bytearray(6)
|
||||
if type(general) in (tuple, list):
|
||||
for i in range(len(general)):
|
||||
if i > 5: break
|
||||
_keys[i] = general[i]
|
||||
else:
|
||||
_keys[0] = general
|
||||
# Pack the mouse state as described by the input report
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_rep, bytes([special & 0xFF, 0]) + _keys)
|
||||
if release:
|
||||
time.sleep_ms(10)
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_rep, b'\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
def notify_battery(self, level):
|
||||
if self.is_connected():
|
||||
self.battery_level = max(min(level, 100), 0)
|
||||
# Notifies the client by writing to the battery level handle.
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_bat, struct.pack("<B", self.battery_level))
|
||||
|
||||
def notify_str(self, string, delay=0):
|
||||
for char in str(string):
|
||||
char = max(min(ord(char), 127), 0)
|
||||
self.notify_hid( 0x02 if _KEYCODE[char] >> 7 else 0x00, _KEYCODE[char] & 0x7F)
|
||||
time.sleep_ms(20 + delay)
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
'''Get mac address'''
|
||||
return hexlify(self._ble.config('mac')[1]).decode()
|
||||
152
boards/default_src/micropython/origin/build/lib/ble_hid_mouse.py
Normal file
152
boards/default_src/micropython/origin/build/lib/ble_hid_mouse.py
Normal file
@@ -0,0 +1,152 @@
|
||||
"""
|
||||
Bluetooth-HID-Mouse
|
||||
|
||||
Micropython library for the Bluetooth-HID-Mouse
|
||||
=======================================================
|
||||
#https://github.com/Heerkog/MicroPythonBLEHID
|
||||
|
||||
@dahanzimin From the Mixly Team
|
||||
"""
|
||||
import bluetooth
|
||||
import struct, time
|
||||
from micropython import const
|
||||
from ubinascii import hexlify
|
||||
from ble_advertising import advertising_payload
|
||||
from bluetooth import UUID, FLAG_READ, FLAG_WRITE ,FLAG_NOTIFY, FLAG_WRITE_NO_RESPONSE
|
||||
|
||||
_IRQ_CENTRAL_CONNECT = const(1)
|
||||
_IRQ_CENTRAL_DISCONNECT = const(2)
|
||||
_IRQ_MTU_EXCHANGED = const(21)
|
||||
_IRQ_CONNECTION_UPDATE = const(27)
|
||||
_IRQ_PASSKEY_ACTION = const(31)
|
||||
_PASSKEY_ACTION_INPUT = const(2)
|
||||
_PASSKEY_ACTION_DISP = const(3)
|
||||
_PASSKEY_ACTION_NUMCMP = const(4)
|
||||
|
||||
_HID_INPUT_REPORT = const(b'\x05\x01\t\x02\xa1\x01\x85\x01\t\x01\xa1\x00\x05\t\x19\x01)\x03\x15\x00%\x01\x95\x03u\x01\x81\x02\x95\x01u\x05\x81\x03\x05\x01\t0\t1\t8\x15\x81%\x7fu\x08\x95\x03\x81\x06\xc0\xc0')
|
||||
|
||||
_DIS = (UUID(0x180A), ( (UUID(0x2A24), FLAG_READ),
|
||||
(UUID(0x2A25), FLAG_READ),
|
||||
(UUID(0x2A26), FLAG_READ),
|
||||
(UUID(0x2A27), FLAG_READ),
|
||||
(UUID(0x2A28), FLAG_READ),
|
||||
(UUID(0x2A29), FLAG_READ),
|
||||
(UUID(0x2A50), FLAG_READ), ), )
|
||||
|
||||
_BAS = (UUID(0x180F), ( (UUID(0x2A19), FLAG_READ | FLAG_NOTIFY, (
|
||||
(UUID(0x2902), 0x01 | 0x02),
|
||||
(UUID(0x2904), 0x01),)), ), )
|
||||
|
||||
_HIDS = (UUID(0x1812), ((UUID(0x2A4A), FLAG_READ),
|
||||
(UUID(0x2A4B), FLAG_READ),
|
||||
(UUID(0x2A4C), FLAG_READ | FLAG_WRITE | FLAG_WRITE_NO_RESPONSE),
|
||||
(UUID(0x2A4D), FLAG_READ | FLAG_NOTIFY, (
|
||||
(UUID(0x2902), 0x01 | 0x02),
|
||||
(UUID(0x2908), 0x01 | 0x02), )),
|
||||
(UUID(0x2A4E), FLAG_READ | FLAG_WRITE | FLAG_WRITE_NO_RESPONSE), ), )
|
||||
|
||||
class Mouse:
|
||||
def __init__(self, name=None, passkey=1234, battery_level=100):
|
||||
if (name is '') or (name is None):
|
||||
name = "Mixgo_" + self.mac[-6:].upper()
|
||||
print("Mouse name:", name)
|
||||
|
||||
self._ble = bluetooth.BLE()
|
||||
self._ble.active(True)
|
||||
self._ble.irq(self._irq)
|
||||
self._ble.config(gap_name=name)
|
||||
self._ble.config(mtu=23)
|
||||
self.device_state = False
|
||||
self.conn_handle = None
|
||||
self.passkey = passkey
|
||||
self.battery_level = battery_level
|
||||
|
||||
handles = self._ble.gatts_register_services((_DIS, _BAS, _HIDS))
|
||||
self._service_characteristics(handles)
|
||||
self._payload = advertising_payload(name=name, services=[UUID(0x1812)], appearance=const(962))
|
||||
self.advertise()
|
||||
|
||||
def _irq(self, event, data):
|
||||
# Interrupt request callback function
|
||||
if event == _IRQ_CENTRAL_CONNECT:
|
||||
self.conn_handle, _, _ = data
|
||||
print("Mouse connected: ", self.conn_handle)
|
||||
self.device_state = True
|
||||
elif event == _IRQ_CENTRAL_DISCONNECT:
|
||||
self.conn_handle = None
|
||||
conn_handle, addr_type, addr = data
|
||||
print("Mouse disconnected: ", conn_handle)
|
||||
self.advertise()
|
||||
self.device_state = False
|
||||
elif event == _IRQ_MTU_EXCHANGED:
|
||||
conn_handle, mtu = data
|
||||
self._ble.config(mtu=mtu)
|
||||
print("MTU exchanged: ", mtu)
|
||||
elif event == _IRQ_CONNECTION_UPDATE:
|
||||
self.conn_handle, _, _, _, _ = data
|
||||
print("Connection update")
|
||||
elif event == _IRQ_PASSKEY_ACTION:
|
||||
conn_handle, action, passkey = data
|
||||
print("Passkey action", conn_handle, action, passkey)
|
||||
if action == _PASSKEY_ACTION_NUMCMP:
|
||||
self._ble.gap_passkey(conn_handle, action, False)
|
||||
elif action == _PASSKEY_ACTION_DISP:
|
||||
print("Displaying passkey")
|
||||
self._ble.gap_passkey(conn_handle, action, self.passkey)
|
||||
elif action == _PASSKEY_ACTION_INPUT:
|
||||
print(" Prompting for passkey")
|
||||
self._ble.gap_passkey(conn_handle, action, None)
|
||||
else:
|
||||
print("unknown action")
|
||||
#else:
|
||||
#print("Unhandled IRQ event: ", event, data)
|
||||
|
||||
def _service_characteristics(self, handles):
|
||||
(h_mod, h_ser, h_fwr, h_hwr, h_swr, h_man, h_pnp) = handles[0]
|
||||
(self.h_bat, h_ccc, h_bfmt,) = handles[1]
|
||||
(h_info, h_hid, h_ctrl, self.h_rep, _, h_d1, h_proto) = handles[2]
|
||||
|
||||
# Write DIS characteristics.
|
||||
self._ble.gatts_write(h_mod, b'1')
|
||||
self._ble.gatts_write(h_ser, b'1')
|
||||
self._ble.gatts_write(h_fwr, b'1')
|
||||
self._ble.gatts_write(h_hwr, b'1')
|
||||
self._ble.gatts_write(h_swr, b'1')
|
||||
self._ble.gatts_write(h_man, b'Homebrew')
|
||||
self._ble.gatts_write(h_pnp, struct.pack("<BHHH", 0x01, 0xFE61, 0x01, 0x0123))
|
||||
# Write BAS characteristics.
|
||||
self._ble.gatts_write(self.h_bat, struct.pack("<B", self.battery_level))
|
||||
self._ble.gatts_write(h_bfmt, b'\x04\x00\xad\x27\x01\x00\x00')
|
||||
self._ble.gatts_write(h_ccc, b'\x00\x00')
|
||||
# Write service characteristics
|
||||
self._ble.gatts_write(h_info, b"\x01\x01\x00\x02")
|
||||
self._ble.gatts_write(h_hid, _HID_INPUT_REPORT)
|
||||
self._ble.gatts_write(self.h_rep, b'\x00\x00\x00\x00')
|
||||
self._ble.gatts_write(h_d1, b'\x01\x01')
|
||||
self._ble.gatts_write(h_proto, b"\x01")
|
||||
|
||||
def is_connected(self):
|
||||
return self.device_state
|
||||
|
||||
def advertise(self, interval_us=100000):
|
||||
print("Starting advertising")
|
||||
self._ble.gap_advertise(interval_us, adv_data=self._payload)
|
||||
|
||||
def notify_hid(self, keys=0, move=(0, 0), wheel=0, release=True):
|
||||
if self.is_connected():
|
||||
# Pack the mouse state as described by the input report
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_rep, bytes([keys & 0x0F, move[0] & 0xFF, move[1] & 0xFF, wheel & 0xFF]))
|
||||
if release:
|
||||
time.sleep_ms(10)
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_rep, b'\x00\x00\x00\x00')
|
||||
|
||||
def notify_battery(self, level):
|
||||
if self.is_connected():
|
||||
self.battery_level = max(min(level, 100), 0)
|
||||
# Notifies the client by writing to the battery level handle.
|
||||
self._ble.gatts_notify(self.conn_handle, self.h_bat, struct.pack("<B", self.battery_level))
|
||||
|
||||
@property
|
||||
def mac(self):
|
||||
'''Get mac address'''
|
||||
return hexlify(self._ble.config('mac')[1]).decode()
|
||||
65
boards/default_src/micropython/origin/build/lib/ds18b20.py
Normal file
65
boards/default_src/micropython/origin/build/lib/ds18b20.py
Normal file
@@ -0,0 +1,65 @@
|
||||
# DS18x20 temperature sensor driver for MicroPython.
|
||||
# MIT license; Copyright (c) 2016 Damien P. George
|
||||
|
||||
import onewire
|
||||
from machine import Pin
|
||||
from micropython import const
|
||||
|
||||
_CONVERT = const(0x44)
|
||||
_RD_SCRATCH = const(0xBE)
|
||||
_WR_SCRATCH = const(0x4E)
|
||||
|
||||
class DS18X20:
|
||||
__species = {}
|
||||
__first_init = True
|
||||
def __new__(cls, pin, *args, **kwargs):
|
||||
if pin not in cls.__species.keys():
|
||||
cls.__first_init = True
|
||||
cls.__species[pin] = object.__new__(cls)
|
||||
return cls.__species[pin]
|
||||
|
||||
def __init__(self, pin):
|
||||
if self.__first_init:
|
||||
self.__first_init = False
|
||||
self._ow = onewire.OneWire(Pin(pin, pull=Pin.PULL_UP))
|
||||
self._buf = bytearray(9)
|
||||
self._roms = self.scan()
|
||||
|
||||
def scan(self):
|
||||
return [rom for rom in self._ow.scan() if rom[0] in (0x10, 0x22, 0x28)]
|
||||
|
||||
def convert_temp(self):
|
||||
self._ow.reset(True)
|
||||
self._ow.writebyte(self._ow.SKIP_ROM)
|
||||
self._ow.writebyte(_CONVERT)
|
||||
|
||||
def read_scratch(self, rom):
|
||||
self._ow.reset(True)
|
||||
self._ow.select_rom(rom)
|
||||
self._ow.writebyte(_RD_SCRATCH)
|
||||
self._ow.readinto(self._buf)
|
||||
if self._ow.crc8(self._buf):
|
||||
raise Exception("CRC error")
|
||||
return self._buf
|
||||
|
||||
def read_temp(self, rom):
|
||||
buf = self.read_scratch(rom)
|
||||
if rom[0] == 0x10:
|
||||
if buf[1]:
|
||||
t = buf[0] >> 1 | 0x80
|
||||
t = -((~t + 1) & 0xFF)
|
||||
else:
|
||||
t = buf[0] >> 1
|
||||
return t - 0.25 + (buf[7] - buf[6]) / buf[7]
|
||||
else:
|
||||
t = buf[1] << 8 | buf[0]
|
||||
if t & 0x8000: # sign bit set
|
||||
t = -((t ^ 0xFFFF) + 1)
|
||||
return t / 16
|
||||
|
||||
def temperature(self):
|
||||
temp = []
|
||||
self.convert_temp()
|
||||
for rom in self._roms:
|
||||
temp.append(round(self.read_temp(rom), 2))
|
||||
return temp [0] if len(temp) == 1 else tuple(temp)
|
||||
@@ -20,115 +20,198 @@ _weather_alarm="http://api.seniverse.com/v3/weather/alarm.json?" #气象灾害
|
||||
_life_suggestion="http://api.seniverse.com/v3/life/suggestion.json?" #生活指数
|
||||
_air_now="http://api.seniverse.com/v3/air/now.json?" #空气质量实况
|
||||
_air_daily="http://api.seniverse.com/v3/air/daily.json?" #逐日空气质量预报
|
||||
_tide_daily="http://api.seniverse.com/v3/tide/daily.json?" #逐小时潮汐预报
|
||||
_air_hourly="http://api.seniverse.com/v3/air/hourly.json?" #逐时空气质量预报
|
||||
_tide_daily="http://api.seniverse.com/v3/tide/daily.json?" #逐时潮汐预报
|
||||
_geo_sun="http://api.seniverse.com/v3/geo/sun.json?" #日出日落
|
||||
_geo_moon="http://api.seniverse.com/v3/geo/moon.json?" #月出月落和月相
|
||||
_location_search="http://api.seniverse.com/v3/location/search.json?" #城市搜索
|
||||
|
||||
#数据请求
|
||||
def _urequests_api(url):
|
||||
try:
|
||||
results=json.loads(urequests.post(url).text)
|
||||
except Exception as e:
|
||||
raise RuntimeError("API request failed or WiFi is not connected",e)
|
||||
|
||||
if "status" in results.keys():
|
||||
raise ValueError(results["status"])
|
||||
if "results" in results.keys():
|
||||
return results["results"]
|
||||
|
||||
#天气实况 https://docs.seniverse.com/api/weather/now.html
|
||||
def weather_now(key,location):
|
||||
url="{}key={}&location={}".format(_weather_now,key,location)
|
||||
results=_urequests_api(url)[0]
|
||||
return results['now']
|
||||
class API_BASE:
|
||||
_results = None
|
||||
def _urequests_api(self, url):
|
||||
try:
|
||||
results=json.loads(urequests.post(url).text)
|
||||
except Exception as e:
|
||||
raise RuntimeError("API request failed or WiFi is not connected",e)
|
||||
|
||||
if "status" in results.keys():
|
||||
raise ValueError(results["status"])
|
||||
if "results" in results.keys():
|
||||
return results["results"]
|
||||
|
||||
#天气实况 https://docs.seniverse.com/api/weather/now.html
|
||||
class Weather_now(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&location={}".format(_weather_now, key, location)
|
||||
self._results = self._urequests_api(url)[0]['now']
|
||||
|
||||
def analysis(self, key=None):
|
||||
if key is None:
|
||||
return self._results
|
||||
else:
|
||||
return self._results[key]
|
||||
|
||||
Weather_now = Weather_now()
|
||||
|
||||
#逐日天气预报 https://docs.seniverse.com/api/weather/daily.html
|
||||
def weather_daily(key,location,days=1):
|
||||
url="{}key={}&location={}&days={}".format(_weather_daily,key,location,days)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['daily'])):
|
||||
data.append(results['daily'][i])
|
||||
return tuple(data)
|
||||
class Weather_daily(API_BASE):
|
||||
def request(self, key, location, days=1):
|
||||
url = "{}key={}&location={}&days={}".format(_weather_daily, key, location, days)
|
||||
self._results = self._urequests_api(url)[0]['daily']
|
||||
|
||||
def analysis(self, days=1, key=None):
|
||||
if key is None:
|
||||
return self._results[days]
|
||||
else:
|
||||
return self._results[days][key]
|
||||
|
||||
Weather_daily = Weather_daily()
|
||||
|
||||
#逐时天气预报 https://docs.seniverse.com/api/weather/hourly.html
|
||||
def weather_hourly(key,location,hours=1):
|
||||
url="{}key={}&location={}&hours={}".format(_weather_hourly,key,location,hours)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['hourly'])):
|
||||
data.append(results['hourly'][i])
|
||||
return tuple(data)
|
||||
class Weather_hourly(API_BASE):
|
||||
def request(self, key, location, hours=1):
|
||||
url = "{}key={}&location={}&hours={}".format(_weather_hourly, key, location, hours)
|
||||
self._results = self._urequests_api(url)[0]['hourly']
|
||||
|
||||
#气象灾害预警 https://docs.seniverse.com/api/weather/alarm.html
|
||||
def weather_alarm(key,location):
|
||||
url="{}key={}&location={}".format(_weather_alarm,key,location)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['alarms'])):
|
||||
data.append(results['alarms'][i])
|
||||
return tuple(data)
|
||||
def analysis(self, hours=1, key=None):
|
||||
if key is None:
|
||||
return self._results[hours]
|
||||
else:
|
||||
return self._results[hours][key]
|
||||
|
||||
#生活指数 https://docs.seniverse.com/api/life/suggestion.html
|
||||
def life_suggestion(key,location,days=1):
|
||||
url="{}key={}&location={}&days={}".format(_life_suggestion,key,location,days)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['suggestion'])):
|
||||
data.append(results['suggestion'][i])
|
||||
return tuple(data)
|
||||
#Weather_hourly = Weather_hourly() #暂不开启
|
||||
|
||||
#空气质量实况 https://docs.seniverse.com/api/air/now.html
|
||||
def air_now(key,location):
|
||||
url="{}key={}&location={}&scope=city".format(_air_now,key,location)
|
||||
results=_urequests_api(url)[0]
|
||||
return results['air']['city']
|
||||
|
||||
#逐日空气质量预报 https://docs.seniverse.com/api/air/daily5d.html
|
||||
def air_daily(key,location,days=1):
|
||||
url="{}key={}&location={}&days={}".format(_air_daily,key,location,days)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['daily'])):
|
||||
data.append(results['daily'][i])
|
||||
return tuple(data)
|
||||
class Air_now(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&location={}&scope=city".format(_air_now, key, location)
|
||||
self._results = self._urequests_api(url)[0]['air']['city']
|
||||
|
||||
#逐时潮汐预报 https://docs.seniverse.com/api/ocean/tide.html
|
||||
def tide_daily(key,location):
|
||||
url="{}key={}&location={}&days=1".format(_tide_daily,key,location)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['ports'])):
|
||||
data.append({'port':results['ports'][i]['port'],
|
||||
'tide':results['ports'][i]['data'][0]['tide'],
|
||||
'range':results['ports'][i]['data'][0]['range']})
|
||||
return tuple(data)
|
||||
def analysis(self, key=None):
|
||||
if key is None:
|
||||
return self._results
|
||||
else:
|
||||
return self._results[key]
|
||||
|
||||
Air_now = Air_now()
|
||||
|
||||
#逐日空气质量预报 https://docs.seniverse.com/api/air/daily5d.html
|
||||
class Air_daily(API_BASE):
|
||||
def request(self, key, location, days=1):
|
||||
url = "{}key={}&location={}&days={}".format(_air_daily, key, location, days)
|
||||
self._results = self._urequests_api(url)[0]['daily']
|
||||
|
||||
def analysis(self, days=1, key=None):
|
||||
if key is None:
|
||||
return self._results[days]
|
||||
else:
|
||||
return self._results[days][key]
|
||||
|
||||
Air_daily= Air_daily()
|
||||
|
||||
#逐时空气质量预报 https://docs.seniverse.com/api/air/hourly5d.html
|
||||
class Air_hourly(API_BASE):
|
||||
def request(self, key, location, hours=1):
|
||||
url = "{}key={}&location={}&hours={}&days=1".format(_air_hourly, key, location, hours)
|
||||
self._results = self._urequests_api(url)[0]['hourly']
|
||||
|
||||
def analysis(self, hours=1, key=None):
|
||||
if key is None:
|
||||
return self._results[hours]
|
||||
else:
|
||||
return self._results[hours][key]
|
||||
|
||||
#Air_hourly = Air_hourly() #暂不开启
|
||||
|
||||
#气象灾害预警 https://docs.seniverse.com/api/weather/alarm.html
|
||||
class Weather_alarm(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&location={}".format(_weather_alarm, key, location)
|
||||
results = self._urequests_api(url)[0]['alarms']
|
||||
self._results = results[0] if results else {}
|
||||
|
||||
def analysis(self, key=None):
|
||||
if key is None:
|
||||
return self._results
|
||||
if key in self._results.keys():
|
||||
return self._results[key]
|
||||
|
||||
Weather_alarm = Weather_alarm()
|
||||
|
||||
#生活指数 https://docs.seniverse.com/api/life/suggestion.html
|
||||
class Life_suggestion(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&location={}".format(_life_suggestion, key, location)
|
||||
self._results = self._urequests_api(url)[0]['suggestion']
|
||||
|
||||
def analysis(self, key=None, brief=False):
|
||||
if key is None:
|
||||
return self._results
|
||||
else:
|
||||
return self._results[key]['brief'] if brief else self._results[key]['details']
|
||||
|
||||
Life_suggestion = Life_suggestion()
|
||||
|
||||
#24时潮汐预报 https://docs.seniverse.com/api/ocean/tide.html
|
||||
class Tide_daily(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&location={}&days=1".format(_tide_daily, key, location)
|
||||
self._results = self._urequests_api(url)[0]['ports'][0]['data'][0]
|
||||
|
||||
def analysis(self, key=None):
|
||||
if key is None:
|
||||
return self._results
|
||||
else:
|
||||
key = key.split(',')
|
||||
if len(key) == 1:
|
||||
return self._results[key[0]]
|
||||
if len(key) == 2:
|
||||
return self._results['range'][int(key[0])][key[1]]
|
||||
|
||||
Tide_daily = Tide_daily()
|
||||
|
||||
#日出日落 https://docs.seniverse.com/api/geo/sun.html
|
||||
def geo_sun(key,location,days=1):
|
||||
url="{}key={}&location={}&days={}".format(_geo_sun,key,location,days)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['sun'])):
|
||||
data.append(results['sun'][i])
|
||||
return tuple(data)
|
||||
|
||||
class Geo_sun(API_BASE):
|
||||
def request(self, key, location, days=1):
|
||||
url = "{}key={}&location={}&days={}".format(_geo_sun, key, location, days)
|
||||
self._results = self._urequests_api(url)[0]['sun']
|
||||
|
||||
def analysis(self, days=1, key=None):
|
||||
if key is None:
|
||||
return self._results[days]
|
||||
else:
|
||||
return self._results[days][key]
|
||||
|
||||
Geo_sun = Geo_sun()
|
||||
|
||||
#月出月落和月相 https://docs.seniverse.com/api/geo/moon.html
|
||||
def geo_moon(key,location,days=1):
|
||||
url="{}key={}&location={}&days={}".format(_geo_moon,key,location,days)
|
||||
results=_urequests_api(url)[0]
|
||||
data=[]
|
||||
for i in range(len(results['moon'])):
|
||||
data.append(results['moon'][i])
|
||||
return tuple(data)
|
||||
|
||||
class Geo_moon(API_BASE):
|
||||
def request(self, key, location, days=1):
|
||||
url = "{}key={}&location={}&days={}".format(_geo_moon, key, location, days)
|
||||
self._results = self._urequests_api(url)[0]['moon']
|
||||
|
||||
def analysis(self, days=1, key=None):
|
||||
if key is None:
|
||||
return self._results[days]
|
||||
else:
|
||||
return self._results[days][key]
|
||||
|
||||
Geo_moon = Geo_moon()
|
||||
|
||||
#城市搜索 https://docs.seniverse.com/api/fct/search.html
|
||||
def location_search(key,location):
|
||||
url="{}key={}&q={}&limit=50".format(_location_search,key,location)
|
||||
results=_urequests_api(url)
|
||||
data=[]
|
||||
for i in range(len(results)):
|
||||
data.append(results[i])
|
||||
return tuple(data)
|
||||
class Location_search(API_BASE):
|
||||
def request(self, key, location):
|
||||
url = "{}key={}&q={}&limit=50".format(_location_search, key, location)
|
||||
results = self._urequests_api(url)
|
||||
self._results = results[0] if results else {}
|
||||
|
||||
def analysis(self, key=None):
|
||||
if key is None:
|
||||
return self._results
|
||||
else:
|
||||
if key in self._results.keys():
|
||||
return self._results[key]
|
||||
|
||||
Location_search = Location_search()
|
||||
|
||||
@@ -43,7 +43,7 @@ def request(method, url, data=None, json=None, headers={}, stream=None, parse_he
|
||||
if proto == "http:":
|
||||
port = 80
|
||||
elif proto == "https:":
|
||||
import ussl
|
||||
import ssl
|
||||
port = 443
|
||||
else:
|
||||
raise ValueError("Unsupported protocol: " + proto)
|
||||
@@ -63,7 +63,7 @@ def request(method, url, data=None, json=None, headers={}, stream=None, parse_he
|
||||
try:
|
||||
s.connect(ai[-1])
|
||||
if proto == "https:":
|
||||
s = ussl.wrap_socket(s, server_hostname=host)
|
||||
s = ssl.wrap_socket(s, server_hostname=host)
|
||||
s.write(b"%s /%s HTTP/1.0\r\n" % (method, path))
|
||||
if not "Host" in headers:
|
||||
s.write(b"Host: %s\r\n" % host)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,7 +5,7 @@ Micropython library for the MINI_WCH(TOUCH*2, MIC*1, Buzzer*1, PWM*2, Matrix8x12
|
||||
=======================================================
|
||||
@dahanzimin From the Mixly Team
|
||||
"""
|
||||
import time
|
||||
import time, math
|
||||
from esp import flash_read
|
||||
from micropython import const
|
||||
from framebuf import FrameBuffer, MONO_VLSB
|
||||
@@ -215,6 +215,12 @@ class BOT035(FrameBuffer):
|
||||
self.show()
|
||||
time.sleep_ms(speed)
|
||||
|
||||
def pointern(self, x=_LEDS_W // 2, y=_LEDS_H // 2, l=_LEDS_H // 2, angle=0):
|
||||
radian = math.radians(angle)
|
||||
self.fill(0)
|
||||
self.line(x, y, round(x + l * math.sin(radian)), round(y - l * math.cos(radian)), 1)
|
||||
self.show()
|
||||
|
||||
def _wreg(self, reg, val):
|
||||
'''Write memory address'''
|
||||
self._i2c.writeto_mem(_BOT035_ADDRESS, reg, val.to_bytes(1, 'little'))
|
||||
|
||||
Reference in New Issue
Block a user