commit 1ac8e9b4041e81519a8015435daf0e169d44f746 Author: momom Date: Sat Apr 4 13:06:12 2026 +0800 init diff --git a/LICENSE.TXT b/LICENSE.TXT new file mode 100644 index 0000000..9740f59 --- /dev/null +++ b/LICENSE.TXT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 QmiTek (https://qmikeji.cn) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..f24bcf1 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# Makergen 开发工具 + +郭铭浩说了,文档他写 \ No newline at end of file diff --git a/config.json b/config.json new file mode 100644 index 0000000..53e2e13 --- /dev/null +++ b/config.json @@ -0,0 +1,26 @@ +{ + "name": { + "zh-cn": "makergen开发工具", + "en": "makergen SDK" + }, + "description": { + "zh-cn": "makergen开发工具。允许用户连接makergen页面", + "en": "makergen SDK for makergen users" + }, + "author": "QmiTek", + "email": "qmi@qmikeji.cn", + "license": "MIT", + "isBoard": false, + "id": "makergen", + "platform": ["win","mac","web","linux"], + "version": "0.0.1", + "asset": { + "python": { + "dir": "python/", + "main": "main.ts", + "dependencies": { + "websocket-client":"1.9.0" + } + } +} +} \ No newline at end of file diff --git a/python/_images/featured.png b/python/_images/featured.png new file mode 100644 index 0000000..6d40a6a Binary files /dev/null and b/python/_images/featured.png differ diff --git a/python/_images/icon.svg b/python/_images/icon.svg new file mode 100644 index 0000000..37fec90 --- /dev/null +++ b/python/_images/icon.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/python/_menus/index.json b/python/_menus/index.json new file mode 100644 index 0000000..0db3279 --- /dev/null +++ b/python/_menus/index.json @@ -0,0 +1,3 @@ +{ + +} diff --git a/python/libraries/LICENSE b/python/libraries/LICENSE new file mode 100644 index 0000000..e412f7a --- /dev/null +++ b/python/libraries/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2026 QmiTek (https://qmikeji.cn) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/python/libraries/makergen/__init__.py b/python/libraries/makergen/__init__.py new file mode 100644 index 0000000..a054937 --- /dev/null +++ b/python/libraries/makergen/__init__.py @@ -0,0 +1,7 @@ +"""适配makergen的Python SDK""" + +__version__ = '0.1.0' + +from makergen.core import Device + +__all__ = ["Device"] diff --git a/python/libraries/makergen/core.py b/python/libraries/makergen/core.py new file mode 100644 index 0000000..5b88bfd --- /dev/null +++ b/python/libraries/makergen/core.py @@ -0,0 +1,85 @@ +import json +import threading +import time +from json import JSONDecodeError +from typing import Callable, Optional + +import websocket + + +class ServerException(Exception): + pass + + +class Device: + def __init__(self, device_id: str, device_key: str, + on_msg_callback: Optional[Callable[[str, any], None]] = lambda point, value : print(point, value), + on_error_callback: Optional[Callable[[Exception], None]] = lambda error: print(error), + base_url: str = "wss://api.makergen.cn"): + """ + 创建一个设备对象。需要调用connect方法才能真正连接。 + :param device_id: 设备ID,在控制台设备管理中显示 + :param device_key: Device Key,在控制台设备管理中显示 + :param on_msg_callback: 当收到消息后的回调。接收两个参数,第一个参数为控制点,字符串型;第二个参数为控制值,任意类型 + :param on_error_callback: 当遇到错误时的回调。接收一个参数,为错误对象;若遇到服务器或页面发送的消息不合规,传入ServerException对象 + :param base_url: makergen的基础URL,通常为wss://api.makergen.cn + """ + url = f"{base_url if base_url[-1] == '/' else base_url + "/"}ws/device/{device_id}?key={device_key}" + print(url) + self.ws = websocket.WebSocketApp( + url, + on_open=self._on_open, + on_message=self._on_message, + on_close=self._on_close, + on_error=self._on_error, + ) + self.on_msg_callback = on_msg_callback if on_msg_callback is not None else lambda _, __ : None + self.on_error_callback = on_error_callback if on_error_callback is not None else lambda _ : None + self.is_connected = False + + def _on_open(self, ws): + self.is_connected = True + def _on_close(self, ws, close_status_code, close_msg): + self.is_connected = False + + def _on_message(self, ws, message): + try: + message_str = json.loads(message)["payload"] + self.on_msg_callback(message_str["point"], message_str["value"]) + except (KeyError, JSONDecodeError): + self.on_error_callback(ServerException("Page or server sent an invalid message")) + except Exception as e: + self.on_error_callback(e) + + def _on_error(self, ws, error): + self.on_error_callback(error) + + def send_data(self, point: str, value: str): + self.ws.send(json.dumps({ + "type": "data", + "payload": { + "point": point, + "value": value + }, + "timestamp": int(time.time() * 1000) + })) + + def connect(self, timeout: float = 5.0): + """ + 在新线程中运行客户端循环(推荐) + """ + wst = threading.Thread(target=self.ws.run_forever) + wst.daemon = True + wst.start() + start_time = time.time() + while not self.is_connected: + if time.time() - start_time > timeout: + if not self.is_connected: + self.on_error_callback(TimeoutError(f"WebSocket connection timed out after {timeout} seconds")) + time.sleep(0.05) + +def main_loop(self): + """ + 在当前线程中运行客户端循环(不推荐) + """ + self.ws.run_forever() \ No newline at end of file diff --git a/python/libraries/requirements.txt b/python/libraries/requirements.txt new file mode 100644 index 0000000..2f738ef --- /dev/null +++ b/python/libraries/requirements.txt @@ -0,0 +1 @@ +websocket-client==1.9.0 diff --git a/python/main.ts b/python/main.ts new file mode 100644 index 0000000..b9cbf27 --- /dev/null +++ b/python/main.ts @@ -0,0 +1,46 @@ + +//% color="#cf1256" iconWidth=50 iconHeight=40 +namespace makergen{ + + //% block="连接设备 设备ID [ID] Device Key [KEY] 基础URL [BASEURL]" blockType="command" + //% ID.shadow="string" + //% KEY.shadow="string" + //% BASEURL.shadow="string" + //% BASEURL.defl="wss://api.makergen.cn" + export function connect(parameter: any, block: any) { + let id=parameter.ID.code; + let key=parameter.KEY.code; + let baseurl=parameter.BASEURL.code; + Generator.addImport(`\nimport makergen\nmakergen_device = makergen.Device(${id},${key},on_msg_callback=makergen_callback, base_url=${baseurl})\n`); + Generator.addCode(`makergen_device.connect()\n`); + } + + //% block="向数据点 [POINT] 发送数据 [VALUE]" blockType="command" + //% POINT.shadow="string" + //% VALUE.shadow="normal" + export function send_msg(parameter: any, block: any) { + let point=parameter.POINT.code; + let value=parameter.VALUE.code; + Generator.addCode(`makergen_device.send_data(${point},str(${value}))\n`); + } + + //% block="当接收到消息时" blockType="hat" + export function on_msg(msg: any) { + Generator.addEvent("makergen_callback", "makergen_callback", "point, value", false); + } + + //% block="---" + export function separator() {} + + //% block="控制点" blockType="reporter" + export function get_point(parameter: any, block: any) { + Generator.addCode(`point`); + } + + //% block="控制值" blockType="reporter" + export function get_value(parameter: any, block: any) { + Generator.addCode(`value`); + } + + +}