Compare commits

..

17 Commits

Author SHA1 Message Date
2b6b7f4db0 State 2024-08-23 11:37:03 +08:00
9ad20dcf4d Actually its OSError 2024-08-23 11:37:03 +08:00
ccec874756 _ 2024-08-23 11:37:03 +08:00
54472c0eee Resgister task 2024-08-23 11:37:03 +08:00
66ca5e9597 conneting 2024-08-23 11:37:03 +08:00
632ee8bfa3 Remove wait_for
OSError raised anyways
2024-08-23 11:37:03 +08:00
506d350d7f Raise if OSError 2024-08-23 11:37:03 +08:00
93e0bd91bf Sep. line 2024-08-23 11:37:03 +08:00
b15490e3b5 {start,end}_session -> [dis]connect 2024-08-23 11:37:03 +08:00
920706fbab Lazy evaluating for debug string command 2024-08-23 11:37:03 +08:00
c0e4d49b7b In 2024-08-23 11:37:03 +08:00
23f484e3d8 Compacting 2024-08-23 11:37:03 +08:00
b0c30d128e try-block 2024-08-23 11:37:03 +08:00
cebac565c4 Fix? 2024-08-23 11:37:03 +08:00
9af7f728e9 Add pytec runnables 2024-08-23 11:37:03 +08:00
bef73df401 PYTHON shell 2024-08-23 11:37:03 +08:00
f1d33f4729 Exactlier wording 2024-08-23 11:37:03 +08:00
7 changed files with 65 additions and 44 deletions

View File

@ -118,6 +118,20 @@
]; ];
}; };
pytec-dev-wrappers = pkgs.runCommandNoCC "pytec-dev-wrappers" {}
''
mkdir -p $out/bin
for program in ${self}/pytec/*.py; do
if [ -x $program ]; then
progname=`basename -s .py $program`
outname=$out/bin/$progname
echo "#!${pkgs.bash}/bin/bash" >> $outname
echo "exec python3 -m pytec.$progname \"\$@\"" >> $outname
chmod 755 $outname
fi
done
'';
thermostat_gui = pkgs.python3Packages.buildPythonPackage { thermostat_gui = pkgs.python3Packages.buildPythonPackage {
pname = "thermostat_gui"; pname = "thermostat_gui";
version = "0.0.0"; version = "0.0.0";
@ -163,6 +177,7 @@
rust rust
openocd openocd
dfu-util dfu-util
pytec-dev-wrappers
] ]
++ (with python3Packages; [ ++ (with python3Packages; [
numpy numpy
@ -174,6 +189,9 @@
pglive pglive
qtextras qtextras
]); ]);
shellHook = ''
export PYTHONPATH=`pwd`/pytec:$PYTHONPATH
'';
}; };
defaultPackage.x86_64-linux = thermostat; defaultPackage.x86_64-linux = thermostat;
}; };

0
pytec/autotune.py Normal file → Executable file
View File

View File

@ -4,7 +4,7 @@ from pytec.aioclient import AsyncioClient
async def main(): async def main():
tec = AsyncioClient() tec = AsyncioClient()
await tec.start_session() # (host="192.168.1.26", port=23) await tec.connect() # (host="192.168.1.26", port=23)
await tec.set_param("s-h", 1, "t0", 20) await tec.set_param("s-h", 1, "t0", 20)
print(await tec.get_pwm()) print(await tec.get_pwm())
print(await tec.get_pid()) print(await tec.get_pid())

0
pytec/plot.py Normal file → Executable file
View File

View File

@ -13,13 +13,14 @@ class AsyncioClient:
self._writer = None self._writer = None
self._command_lock = asyncio.Lock() self._command_lock = asyncio.Lock()
self._report_mode_on = False self._report_mode_on = False
self.timeout = None
async def start_session(self, host="192.168.1.26", port=23): async def connect(self, host="192.168.1.26", port=23):
"""Start session to Thermostat at specified host and port. """Connect to Thermostat at specified host and port.
Example:: Example::
client = AsyncioClient() client = AsyncioClient()
await client.start_session() await client.connect()
""" """
self._reader, self._writer = await asyncio.open_connection(host, port) self._reader, self._writer = await asyncio.open_connection(host, port)
await self._check_zero_limits() await self._check_zero_limits()
@ -28,8 +29,8 @@ class AsyncioClient:
"""Returns True if client is connected""" """Returns True if client is connected"""
return self._writer is not None return self._writer is not None
async def end_session(self): async def disconnect(self):
"""End session to Thermostat""" """Disconnect from the Thermostat"""
if self._writer is None: if self._writer is None:
return return
@ -53,7 +54,9 @@ class AsyncioClient:
async def _read_line(self): async def _read_line(self):
# read 1 line # read 1 line
chunk = await self._reader.readline() chunk = await asyncio.wait_for(
self._reader.readline(), self.timeout
) # Only wait for response until timeout
return chunk.decode("utf-8", errors="ignore") return chunk.decode("utf-8", errors="ignore")
async def _read_write(self, command): async def _read_write(self, command):
@ -67,7 +70,7 @@ class AsyncioClient:
line = await self._read_write(command) line = await self._read_write(command)
response = json.loads(line) response = json.loads(line)
logging.debug(f"{command}: {response}") logging.debug("%s: %s", command, response)
if "error" in response: if "error" in response:
raise CommandError(response["error"]) raise CommandError(response["error"])
return response return response
@ -238,7 +241,7 @@ class AsyncioClient:
self._writer.write("reset\n".encode("utf-8")) self._writer.write("reset\n".encode("utf-8"))
await self._writer.drain() await self._writer.drain()
await self.end_session() await self.disconnect()
async def dfu(self): async def dfu(self):
"""Put the Thermostat in DFU update mode """Put the Thermostat in DFU update mode
@ -251,7 +254,7 @@ class AsyncioClient:
self._writer.write("dfu\n".encode("utf-8")) self._writer.write("dfu\n".encode("utf-8"))
await self._writer.drain() await self._writer.drain()
await self.end_session() await self.disconnect()
async def ipv4(self): async def ipv4(self):
"""Get the IPv4 settings of the Thermostat""" """Get the IPv4 settings of the Thermostat"""

View File

@ -32,20 +32,21 @@ class Thermostat(QObject, metaclass=PropertyMeta):
self._report_mode_task = None self._report_mode_task = None
self._poll_for_report = True self._poll_for_report = True
self.connection_errored = False self.connection_errored = False
self.task = None
super().__init__(parent) super().__init__(parent)
async def start_session(self, host, port): async def start_session(self, host, port):
await self._client.start_session(host, port) await self._client.connect(host, port)
async def run(self): async def run(self):
self.task = asyncio.create_task(self.update_params()) self.task = asyncio.create_task(self.update_params())
while True: while True:
if self.task.done(): if self.task.done():
try: try:
_ = self.task.result() self.task.result()
except asyncio.TimeoutError: except OSError:
logging.error( logging.error(
"Encountered an error while updating parameter tree.", "Encountered an error while polling for information from Thermostat.",
exc_info=True, exc_info=True,
) )
self.connection_error.emit() self.connection_error.emit()
@ -103,7 +104,7 @@ class Thermostat(QObject, metaclass=PropertyMeta):
] ]
async def end_session(self): async def end_session(self):
await self._client.end_session() await self._client.disconnect()
self.connection_errored = False self.connection_errored = False
async def set_ipv4(self, ipv4): async def set_ipv4(self, ipv4):

57
pytec/tec_qt.py Normal file → Executable file
View File

@ -65,6 +65,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.thermostat = Thermostat( self.thermostat = Thermostat(
self, self.report_refresh_spin.value() self, self.report_refresh_spin.value()
) )
self._connecting_task = None
def handle_connection_error(): def handle_connection_error():
self.info_box.display_info_box( self.info_box.display_info_box(
@ -238,40 +239,38 @@ class MainWindow(QtWidgets.QMainWindow):
except: except:
pass pass
def _connecting(self):
self.status_lbl.setText("Connecting...")
self.connect_btn.setText("Stop")
self.conn_menu.host_set_line.setEnabled(False)
self.conn_menu.port_set_spin.setEnabled(False)
@asyncSlot() @asyncSlot()
async def on_connect_btn_clicked(self): async def on_connect_btn_clicked(self):
host, port = ( if (self._connecting_task is None) and (not self.thermostat.connected()):
self.conn_menu.host_set_line.text(), host = self.conn_menu.host_set_line.text()
self.conn_menu.port_set_spin.value(), port = self.conn_menu.port_set_spin.value()
)
self._connecting_task = None self._connecting()
try: self._connecting_task = asyncio.create_task(
if (self._connecting_task is None) or (not self.thermostat.connected()): self.thermostat.start_session(host=host, port=port)
self.status_lbl.setText("Connecting...") )
self.connect_btn.setText("Stop")
self.conn_menu.host_set_line.setEnabled(False)
self.conn_menu.port_set_spin.setEnabled(False)
try:
self._connecting_task = asyncio.wait_for(
self.thermostat.start_session(host=host, port=port), timeout=5
)
await self._connecting_task
except asyncio.TimeoutError:
return
await self._on_connection_changed(True)
else:
if self._connecting_task is not None:
self._connecting_task.cancel()
await self.bail()
# TODO: Remove asyncio.TimeoutError in Python 3.11
except (OSError, asyncio.TimeoutError):
try: try:
await self._connecting_task
except (OSError, asyncio.CancelledError) as exc:
await self.bail() await self.bail()
except ConnectionResetError: if isinstance(exc, asyncio.CancelledError):
pass return
raise
else:
await self._on_connection_changed(True)
finally:
self._connecting_task = None
elif self._connecting_task is not None:
self._connecting_task.cancel()
else:
await self.bail()
@asyncSlot() @asyncSlot()
async def bail(self): async def bail(self):