1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/walkline-ESP32-BLE-Remote_Controller

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Это зеркальный репозиторий, синхронизируется ежедневно с исходного репозитория.
Клонировать/Скачать
remote_controller.py 6.3 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Walkline Отправлено 5 лет назад 16cc1ef
"""
The MIT License (MIT)
Copyright © 2020 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/ESP32-BLE-Remote_Controller
"""
import ubluetooth as bt
import struct
from ble.profile.manager import ProfileManager
from ble.services import *
from ble.characteristics import *
from ble.descriptors import *
from ble.tools import BLETools
from ble.const import BLEConst
PACK = struct.pack
"""
REPORT_MAP_DATA 描述符了一个用户自定义的控制设备
用途为控制音量加减
"""
REPORT_MAP_DATA = [
0x05, 0x0C, # USAGE_PAGE (Consumer Devices)
0x09, 0x01, # USAGE (Consumer Control)
0xA1, 0x01, # COLLECTION (Application)
# 定义 Report ID 和逻辑最大最小值
0x85, 0x01, # REPORT_ID (1)
0x15, 0x00, # LOGICAL_MINIMUM (0)
0x25, 0x01, # LOGICAL_MAXIMUM (1)
# 定义 Report Count 为 1 bit,即只有 1 个数据段
0x95, 0x01, # REPORT_COUNT (1)
# 定义 Report Size 为 1 bit,即每个数据段只能为 0 或 1,因此逻辑值为 0 和 1
0x75, 0x01, # REPORT_SIZE (1)
# 定义用途为 音量减,控制位为 0b1
0x09, 0xEA, # USAGE (Volume Down)
0x81, 0x06, # INPUT (Data,Var,Rel)
# 定义用途为 音量加,控制位为 0b10
0x09, 0xE9, # USAGE (Volume Up)
0x81, 0x06, # INPUT (Data,Var,Rel)
# 补充 7 bit 空位常量凑足 1 byte
# 8 bit - (Report Count * Report Size)
0x95, 0x01, # REPORT_COUNT (1)
0x75, 0x07, # REPORT_SIZE (7)
0x81, 0x03, # INPUT (Cnst,Var,Rel)
0xC0 # END_COLLECTION
]
class BLERemoteController(object):
def __init__(self, device_name="RemoteCon"):
self.__ble = bt.BLE()
self.__device_name = device_name
self.__conn_handle = None
self.__write = self.__ble.gatts_write
self.__read = self.__ble.gatts_read
self.__notify = self.__ble.gatts_notify
self.__profile_manager_adv = ProfileManager()
self.__profile_manager_resp = ProfileManager()
# 定义 HID 设备必须的 3 个服务
self.__profile_manager_adv.add_services(
HumanInterfaceDevice().add_characteristics(
ReportMap(),
Report(),
ProtocolMode(),
HIDInformation(),
HIDControlPoint(),
BootMouseInputReport(),
),
DeviceInformation().add_characteristics(
PNPID(),
),
BatteryService().add_characteristics(
BatteryLevel(),
),
)
# 定义 BLE 设备必须的 2 个服务
self.__profile_manager_resp.add_services(
GenericAccess().add_characteristics(
DeviceName(),
Appearance(),
PeripheralPreferredConnectionParameters(),
CentralAddressResolution(),
),
GenericAttribute().add_characteristics(
ServiceChanged(),
),
)
self.__ble.active(False)
print("activating ble...")
self.__ble.active(True)
print("ble activated")
self.__services = self.__profile_manager_adv.get_services() + self.__profile_manager_resp.get_services()
self.__ble.irq(self.__irq)
self.__register_services()
self.__adv_payload = BLETools.advertising_hid_payload(
services=self.__profile_manager_adv.get_services_uuid(),
appearance=BLEConst.Appearance.HUMAN_INTERFACE_DEVICE_HID
)
self.__resp_payload = BLETools.advertising_resp_payload(
services=self.__profile_manager_resp.get_services_uuid(),
name=self.__device_name
)
self.__advertise()
def __register_services(self):
(
(
self.__handle_report_map,
self.__handle_report,
self.__handle_protocol_mode,
self.__handle_hid_information,
self.__handle_hid_control_point,
self.__handle_boot_mouse_input_report,
),
(
self.__handle_pnp_id,
),
(
self.__handle_battery_level,
),
(
self.__handle_device_name,
self.__handle_appearance,
self.__handle_ppcp,
self.__handle_central_address_resolution,
),
(
self.__handle_service_changed,
),
) = self.__ble.gatts_register_services(self.__services)
print("services registed")
self.__setup_generic_access()
self.__setup_hid()
self.__setup_device_info()
self.update_battery_level()
def __advertise(self, interval_us=100000):
self.__ble.gap_advertise(None)
self.__ble.gap_advertise(interval_us, adv_data=self.__adv_payload, resp_data=self.__resp_payload)
print("advertising...")
def __irq(self, event, data):
if event == BLEConst.IRQ.IRQ_CENTRAL_CONNECT:
self.__conn_handle, _, addr, = data
print("[{}] connected, handle: {}".format(BLETools.decode_mac(addr), self.__conn_handle))
self.__ble.gap_advertise(None)
elif event == BLEConst.IRQ.IRQ_CENTRAL_DISCONNECT:
self.__conn_handle, _, addr, = data
print("[{}] disconnected, handle: {}".format(BLETools.decode_mac(addr), self.__conn_handle))
self.__conn_handle = None
self.__advertise()
else:
print("event: {}, data: {}".format(event, data))
def __setup_hid(self):
self.__write(self.__handle_report_map, bytes(REPORT_MAP_DATA))
self.__write(self.__handle_protocol_mode, PACK("<B", 1))
self.__write(self.__handle_hid_information, PACK("<Hbb", 0x0100, 0x00, 0b0011))
def __setup_device_info(self):
self.__write(self.__handle_pnp_id, PACK("<BHHH", 1, 0x02E5, 0x01, 0x01)) # 由 Bluetooth SIG 分配的公司代码, 乐鑫信息科技, PID, PVer
def __setup_generic_access(self):
self.__write(self.__handle_device_name, PACK("<{}s".format(len(self.__device_name)), self.__device_name.encode()))
self.__write(self.__handle_appearance, PACK("<h", BLEConst.Appearance.HUMAN_INTERFACE_DEVICE_HID))
self.__write(self.__handle_ppcp, PACK("<4h", 40, 80, 10, 300))
self.__write(self.__handle_central_address_resolution, PACK("<b", 1))
def update_battery_level(self):
import random
random.seed(random.randint(-2**16, 2**16))
self.__write(self.__handle_battery_level, PACK("<B", int(random.randint(1, 100))))
if self.__conn_handle is not None:
self.__notify(self.__conn_handle, self.__handle_battery_level)
def send_volume_key(self):
if self.__conn_handle is not None:
self.__write(self.__handle_report, bytes([0x1, 0b1])) # 0x1 为 REPORT_MAP_DATA 中定义的 Report ID
self.__notify(self.__conn_handle, self.__handle_report)
# 发送 0b0 释放按键
self.__write(self.__handle_report, bytes([0x1, 0b0]))
self.__notify(self.__conn_handle, self.__handle_report)
def main():
from machine import Pin
def button_click_cb(p):
remote_controller.send_volume_key()
remote_controller = BLERemoteController()
button = Pin(0, Pin.IN, Pin.PULL_UP)
button.irq(button_click_cb, Pin.IRQ_RISING)
print("button initialized")
if __name__ == "__main__":
main()

Комментарий ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://gitlife.ru/oschina-mirror/walkline-ESP32-BLE-Remote_Controller.git
git@gitlife.ru:oschina-mirror/walkline-ESP32-BLE-Remote_Controller.git
oschina-mirror
walkline-ESP32-BLE-Remote_Controller
walkline-ESP32-BLE-Remote_Controller
master