add device function

This commit is contained in:
flandre 2025-05-13 19:23:10 +08:00
parent 002af887bc
commit 80eb1eea96
4 changed files with 179 additions and 18 deletions

104
cmd_example.ipynb Normal file
View File

@ -0,0 +1,104 @@
{
"cells": [
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-13T11:19:50.850223Z",
"start_time": "2025-05-13T11:19:35.463013Z"
}
},
"cell_type": "code",
"source": "!flandre device connect",
"id": "b9a1cfa42427ea58",
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:67\" [2025-05-13 19:19:38.685] WARNING - retry DeviceCmd.SetConnectionOn\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:67\" [2025-05-13 19:19:41.688] WARNING - retry DeviceCmd.SetConnectionOn\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:67\" [2025-05-13 19:19:44.691] WARNING - retry DeviceCmd.SetConnectionOn\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:67\" [2025-05-13 19:19:47.696] WARNING - retry DeviceCmd.SetConnectionOn\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:67\" [2025-05-13 19:19:50.699] WARNING - retry DeviceCmd.SetConnectionOn\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/BusClient.py:102\" [2025-05-13 19:19:50.699] WARNING - timeout\r\n",
"\"/home/lambda/source/scarlet/flandre/flandre/nodes/Device.py:83\" [2025-05-13 19:19:50.700] ERROR - Device msg: timeout\r\n"
]
}
],
"execution_count": 34
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-13T11:19:54.021623Z",
"start_time": "2025-05-13T11:19:51.402588Z"
}
},
"cell_type": "code",
"source": "!flandre device upload fakename config/device/max-256-120,U=120,M=PWI,S=\\(256\\ 6002\\).txt",
"id": "ac406034e9609c90",
"outputs": [],
"execution_count": 35
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-13T11:19:56.434235Z",
"start_time": "2025-05-13T11:19:54.591188Z"
}
},
"cell_type": "code",
"source": "!flandre device enable",
"id": "ab586d49c1b1ba92",
"outputs": [],
"execution_count": 36
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-13T11:20:10.235636Z",
"start_time": "2025-05-13T11:20:08.501316Z"
}
},
"cell_type": "code",
"source": "!flandre device disable",
"id": "ca701d64ece107ad",
"outputs": [],
"execution_count": 37
},
{
"metadata": {
"ExecuteTime": {
"end_time": "2025-05-13T11:20:20.518130Z",
"start_time": "2025-05-13T11:20:18.355438Z"
}
},
"cell_type": "code",
"source": "!flandre device disconnect",
"id": "43b7940521fe2281",
"outputs": [],
"execution_count": 38
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@ -41,14 +41,14 @@ class BusClient:
self.pub.connect(f'tcp://127.0.0.1:{self.fp}')
self.req_socket = None
if req_socket_str is not None:
self.poller2 = zmq.Poller()
self.sub2 = self.ctx.socket(zmq.SUB)
self.sub2.setsockopt(zmq.SUBSCRIBE, InterruptMsg.magic() + InterruptMsg.eid())
self.poller_for_interrupt = zmq.Poller()
self.sub_for_interrupt = self.ctx.socket(zmq.SUB)
self.sub_for_interrupt.setsockopt(zmq.SUBSCRIBE, InterruptMsg.magic() + InterruptMsg.eid())
# self.sub2.connect(f'tcp://127.0.0.1:{self.bp}')
self.req_socket_str = req_socket_str
self.req_socket = self.ctx.socket(zmq.REQ)
self.poller2.register(self.req_socket, zmq.POLLIN)
self.poller2.register(self.sub2, zmq.POLLIN)
self.poller_for_interrupt.register(self.req_socket, zmq.POLLIN)
self.poller_for_interrupt.register(self.sub_for_interrupt, zmq.POLLIN)
self.req_socket.connect(req_socket_str)
# todo fix poller
@ -78,27 +78,27 @@ class BusClient:
retry_times=114514,
cb_retry=None,
):
self.sub2.connect(f'tcp://127.0.0.1:{self.bp}')
self.sub_for_interrupt.connect(f'tcp://127.0.0.1:{self.bp}')
for _ in range(retry_times):
self.req_socket.send(data)
r = dict(self.poller2.poll(timeout))
r = dict(self.poller_for_interrupt.poll(timeout))
if self.req_socket in r:
self.sub2.disconnect(f'tcp://127.0.0.1:{self.bp}')
self.sub_for_interrupt.disconnect(f'tcp://127.0.0.1:{self.bp}')
return self.req_socket.recv()
if cb_retry is not None:
cb_retry()
self.poller2.unregister(self.req_socket)
self.poller_for_interrupt.unregister(self.req_socket)
self.req_socket.close()
self.req_socket = self.ctx.socket(zmq.REQ)
self.poller2.register(self.req_socket, zmq.POLLIN)
self.poller_for_interrupt.register(self.req_socket, zmq.POLLIN)
self.req_socket.connect(self.req_socket_str)
if self.sub2 in r:
msg = Msg.decode_msg(self.sub2.recv())
if self.sub_for_interrupt in r:
msg = Msg.decode_msg(self.sub_for_interrupt.recv())
if isinstance(msg, InterruptMsg):
if msg.value == interrupt_name:
self.sub2.disconnect(f'tcp://127.0.0.1:{self.bp}')
self.sub_for_interrupt.disconnect(f'tcp://127.0.0.1:{self.bp}')
return None
logging.warning('timeout')
self.sub2.disconnect(f'tcp://127.0.0.1:{self.bp}')
self.sub_for_interrupt.disconnect(f'tcp://127.0.0.1:{self.bp}')
return 'timeout'

View File

@ -6,16 +6,20 @@ import shutil
import subprocess
import tomllib
from enum import Enum, auto
from io import TextIOWrapper
from pathlib import Path
import click
import platformdirs
import zmq
from zmq import Socket
from flandre import C
from flandre import P
from flandre.BusClient import BusClient
from flandre.kde_pyqt6_mainui import kde_pyqt6_mainui
from flandre.nodes.Broker import Broker
from flandre.nodes.Device import Device, DeviceCmd
from flandre.utils.Msg import KillMsg, NodeOnlineMsg, Msg1, Msg2
from flandre.utils.mi import MiSwitch
@ -171,5 +175,57 @@ def status(name):
print(mi.is_on())
device_req: Socket = None
dd: Device = None
@entrypoint.group()
def device():
global device_req
ctx = zmq.Context()
device_req = ctx.socket(zmq.REQ)
device_req.connect(C.live_rep_socket)
global dd
dd = Device()
dd.setup()
@device.command('connect')
def device_connect():
dd.connect()
@device.command('disconnect')
def device_disconnect():
dd.disconnect()
@device.command('enable')
def device_enable():
dd.enable()
@device.command('disable')
def device_disable():
dd.disable()
@device.command('upload')
@click.argument('name')
@click.argument('file', type=click.File('r'))
def device_upload(name, file: TextIOWrapper):
dd.set_name_and_file_only(name, file.read())
@device.command('recvtest')
def device_upload():
ctx = zmq.Context()
pull = ctx.socket(zmq.PULL)
pull.connect(C.live_push_socket)
while True:
b = pull.recv()
print(b.__len__())
if __name__ == '__main__':
entrypoint()

View File

@ -55,15 +55,16 @@ class Device(Node):
self.online()
time.sleep(1)
def d2b(self, cmd: DeviceCmd, v: bytes = b''):
return struct.pack('i', self.magic) + struct.pack('i', cmd.value) + v
@classmethod
def generate_cmd_bytes(cls, cmd: DeviceCmd, v: bytes = b''):
return struct.pack('i', cls.magic) + struct.pack('i', cmd.value) + v
def device_cmd(self, cmd: DeviceCmd, v: bytes = b''):
return self.c.req_interrupt(
self.d2b(cmd, v),
self.generate_cmd_bytes(cmd, v),
interrupt_name='device123',
retry_times=5,
cb_retry=lambda : logger.warning(f'retry {cmd}'),
cb_retry=lambda: logger.warning(f'retry {cmd}'),
)
def connect(self):