Skip to content

Commit

Permalink
Add heartbeat (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
albireox authored Dec 23, 2023
1 parent aaddf07 commit 07a853e
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 21 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## Next version

### 🚀 Added

* [#26](https://github.com/sdss/lvmecp/issues/26) Add heartbeat.


## 0.5.1 - November 24, 2023

### 🔧 Fixed
Expand Down
12 changes: 6 additions & 6 deletions python/lvmecp/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import click
from click_default_group import DefaultGroup

from sdsstools import read_yaml_file
from sdsstools import Configuration
from sdsstools.daemonizer import DaemonGroup, cli_coro

from lvmecp import config, log
Expand Down Expand Up @@ -50,7 +50,7 @@ def lvmecp(ctx, verbose, config_file: str | None):

@lvmecp.group(cls=DaemonGroup, prog="ecp-actor", workdir=os.getcwd())
@click.option(
"--with-simulator/",
"--with-simulator",
is_flag=True,
help="Runs the actor aginst the simulator.",
)
Expand All @@ -59,10 +59,10 @@ def lvmecp(ctx, verbose, config_file: str | None):
async def actor(ctx, with_simulator: bool = False):
"""Runs the actor."""

config_file = ctx.obj["config_file"]
if config_file:
ecp_config = read_yaml_file(config_file)
log.info(f"Using config file {config_file}")
cli_config_file = ctx.obj["config_file"]
if cli_config_file:
ecp_config = Configuration(cli_config_file, base_config=config)
log.info(f"Using config file {cli_config_file}")
else:
ecp_config = deepcopy(config)
log.info("Using internal configuration.")
Expand Down
16 changes: 14 additions & 2 deletions python/lvmecp/actor/actor.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,25 @@ async def start(self, **kwargs):

await super().start(**kwargs)

asyncio.create_task(self._emit_status())
asyncio.create_task(self.emit_status())
asyncio.create_task(self.emit_heartbeat())

return self

async def _emit_status(self, delay: float = 30.0):
async def emit_status(self, delay: float = 30.0):
"""Emits the status on a timer."""

while True:
await self.send_command(self.name, "status", internal=True)
await asyncio.sleep(delay)

async def emit_heartbeat(self, delay: float = 5.0):
"""Updates the heartbeat Modbus variable to indicate the system is alive."""

while True:
try:
await self.plc.modbus["hb_set"].set(True)
except Exception:
self.write("w", "Failed to set heartbeat variable.")
finally:
await asyncio.sleep(delay)
12 changes: 12 additions & 0 deletions python/lvmecp/etc/lvmecp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ modbus:
address: 602
mode: holding_register
group: safety
hb_set:
address: 599
mode: coil
group: safety
hb_ack:
address: 600
mode: coil
group: safety
hb_error:
address: 601
mode: coil
group: safety

safety:
override_local_mode: False
Expand Down
32 changes: 19 additions & 13 deletions python/lvmecp/modbus.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,23 +162,29 @@ async def set(self, value: int | bool):
else:
raise ValueError(f"Invalid block mode {self.mode!r}.")

if self.client.connected:
resp = await func(self.address, value) # type: ignore
else:
async with self.modbus:
try:
if self.client.connected:
resp = await func(self.address, value) # type: ignore
else:
async with self.modbus:
resp = await func(self.address, value) # type: ignore

if resp.function_code > 0x80:
msg = (
f"Invalid response for element "
f"{self.name!r}: 0x{resp.function_code:02X}."
)
if resp.function_code > 0x80:
msg = (
f"Invalid response for element "
f"{self.name!r}: 0x{resp.function_code:02X}."
)
else:
return

if ntries >= MAX_RETRIES:
raise ValueError(msg)
except Exception as err:
msg = f"Error raised while setting {self.name!r}: {err}"

warnings.warn(msg, ECPWarning)
await asyncio.sleep(0.5)
if ntries >= MAX_RETRIES:
raise ValueError(msg)

warnings.warn(msg, ECPWarning)
await asyncio.sleep(0.5)


class Modbus(dict[str, ModbusRegister]):
Expand Down

0 comments on commit 07a853e

Please sign in to comment.