chore: fix templating
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import git
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
def git_push_service_directory(
|
||||
repo_root: str | Path, branch_name: str, service_dir_rel_path: str, commit_msg: str
|
||||
):
|
||||
"""
|
||||
Push newly created service to Gitea
|
||||
"""
|
||||
try:
|
||||
repo = git.Repo(repo_root)
|
||||
|
||||
logger.info(f"Switching to branch '{branch_name}'...")
|
||||
# Create branch if it doesn't exist, then checkout
|
||||
if branch_name in repo.heads:
|
||||
new_branch = repo.heads[branch_name]
|
||||
else:
|
||||
new_branch = repo.create_head(branch_name)
|
||||
new_branch.checkout()
|
||||
|
||||
logger.info(f"Staging files inside: {service_dir_rel_path}...")
|
||||
repo.index.add([service_dir_rel_path])
|
||||
|
||||
# Check if there are changes to avoid empty commit crashes
|
||||
if not repo.is_dirty(index=True, working_tree=False, path=service_dir_rel_path):
|
||||
logger.info("No changes detected. Skipping commit.")
|
||||
return
|
||||
|
||||
logger.info("Committing changes...")
|
||||
repo.index.commit(commit_msg)
|
||||
|
||||
logger.info(f"Pushing branch '{branch_name}' to origin...")
|
||||
origin = repo.remote(name="origin")
|
||||
origin.push(refspec=f"{branch_name}:{branch_name}").raise_if_error()
|
||||
|
||||
logger.info("Successfully pushed!")
|
||||
|
||||
except Exception as e:
|
||||
logger.info(f"Git Operation Failed: {e}")
|
||||
+31
-6
@@ -1,8 +1,9 @@
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import ClassVar
|
||||
|
||||
import yaml
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, field_validator
|
||||
|
||||
from core.enums import ServiceStatus
|
||||
|
||||
@@ -16,12 +17,36 @@ class Service(BaseModel):
|
||||
name: str
|
||||
status: ServiceStatus
|
||||
|
||||
@property
|
||||
def name_upper(self):
|
||||
return self.name.upper()
|
||||
|
||||
@property
|
||||
def name_lower(self):
|
||||
return self.name.lower()
|
||||
|
||||
@property
|
||||
def dir_name(self):
|
||||
return f"{self.id_str}-{self.name_lower}"
|
||||
|
||||
@property
|
||||
def id_str(self):
|
||||
# TODO: max 999 services, enough?
|
||||
return f"{self.id:03d}"
|
||||
|
||||
def to_dict(self):
|
||||
return {"name": self.name, "status": str(self.status)}
|
||||
return {"name": self.name_lower, "status": str(self.status)}
|
||||
|
||||
class Config:
|
||||
use_enum_values = True
|
||||
|
||||
@field_validator("name")
|
||||
@classmethod
|
||||
def validate_name_chars(cls, value: str) -> str:
|
||||
if not re.match(r"^[a-zA-Z0-9-]+$", value):
|
||||
raise ValueError("name can only contain letters, numbers, and dashes")
|
||||
return value
|
||||
|
||||
|
||||
class ServiceRegistry(BaseModel):
|
||||
config_path: ClassVar[str] = str(SERVICE_REGISTRY_FILENAME)
|
||||
@@ -40,11 +65,11 @@ class ServiceRegistry(BaseModel):
|
||||
def get_services(self) -> list[Service]:
|
||||
return [Service(id=svc_id, **svc_data) for svc_id, svc_data in self.services.items()]
|
||||
|
||||
def add_service(self, name: str) -> int:
|
||||
s = Service(id=self.next_available_id, name=name, status=ServiceStatus.ACTIVE)
|
||||
self.services.update({s.id: s.to_dict()})
|
||||
def add_service(self, name: str) -> Service:
|
||||
svc = Service(id=self.next_available_id, name=name, status=ServiceStatus.ACTIVE)
|
||||
self.services.update({svc.id: svc.to_dict()})
|
||||
self.next_available_id += 1
|
||||
with open(self.config_path, "w") as f:
|
||||
yaml.safe_dump(self.model_dump(), f)
|
||||
|
||||
return self.next_available_id
|
||||
return svc
|
||||
|
||||
@@ -8,8 +8,9 @@ SERVICE_DEST_DIR = REPO_ROOT / "services"
|
||||
|
||||
|
||||
def render_new_service_templates(
|
||||
service_id: int,
|
||||
service_name: str,
|
||||
service_id: str,
|
||||
service_name_upper: str,
|
||||
service_name_lower: str,
|
||||
ioc_host: str,
|
||||
ioc_port: int,
|
||||
user: str,
|
||||
@@ -22,9 +23,8 @@ def render_new_service_templates(
|
||||
dst_path=str(SERVICE_DEST_DIR),
|
||||
data={
|
||||
"service_id": service_id,
|
||||
"service_name": service_name,
|
||||
# TODO: make sure this is ok where used (need to replace some chars by '-'?)
|
||||
"service_name_lower": service_name.lower(),
|
||||
"service_name_upper": service_name_upper,
|
||||
"service_name_lower": service_name_lower,
|
||||
# TODO: restrict this, use enum
|
||||
"ioc_host": ioc_host,
|
||||
"ioc_port": ioc_port,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
import git
|
||||
@@ -8,3 +9,10 @@ def get_git_root(path) -> Path:
|
||||
git_root = git_repo.git.rev_parse("--show-toplevel")
|
||||
|
||||
return Path(git_root)
|
||||
|
||||
|
||||
def init_logging(log_level: str = "info"):
|
||||
"""
|
||||
Configure logging -- set log level
|
||||
"""
|
||||
logging.basicConfig(level=getattr(logging, log_level.upper()))
|
||||
|
||||
+18
-6
@@ -1,24 +1,36 @@
|
||||
import typer
|
||||
|
||||
from core.git import git_push_service_directory
|
||||
from core.models import ServiceRegistry
|
||||
from core.render_templates import render_new_service_templates
|
||||
from core.utils import get_git_root, init_logging
|
||||
|
||||
service = typer.Typer(no_args_is_help=True)
|
||||
|
||||
REPO_ROOT = get_git_root(__file__)
|
||||
|
||||
|
||||
@service.command()
|
||||
def add(
|
||||
name: str = typer.Option(..., "--name", "-n"),
|
||||
):
|
||||
init_logging()
|
||||
# TODO: add restriction on name (maybe: [a-zA-Z0-9-])
|
||||
registry = ServiceRegistry.read_from_config()
|
||||
service_id = registry.add_service(name)
|
||||
service = registry.add_service(name)
|
||||
render_new_service_templates(
|
||||
service_id=service_id,
|
||||
service_name=name,
|
||||
ioc_host="",
|
||||
ioc_port=9999,
|
||||
user="",
|
||||
service_id=service.id_str,
|
||||
service_name_upper=service.name_upper,
|
||||
service_name_lower=service.name_lower,
|
||||
ioc_host="ex-host", # TODO
|
||||
ioc_port=9999, # TODO
|
||||
user="user", # TODO
|
||||
)
|
||||
git_push_service_directory(
|
||||
repo_root=REPO_ROOT,
|
||||
branch_name=f"feature/add-service-{service.name_lower}",
|
||||
service_dir_rel_path=f"services/{service.dir_name}",
|
||||
commit_msg=f"feature: add new service {service.name_lower}",
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
next_available_id: 6
|
||||
next_available_id: 5
|
||||
services:
|
||||
0:
|
||||
name: master
|
||||
@@ -15,6 +15,3 @@ services:
|
||||
4:
|
||||
name: cool-service
|
||||
status: active
|
||||
5:
|
||||
name: cool-service
|
||||
status: active
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
[project]
|
||||
name = "agebd-cool-service"
|
||||
version = "0.1.0"
|
||||
description = "AGEBD-COOL-SERVICE Service"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"agebd==1.2.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=8.4.2",
|
||||
"ruff>=0.15.20",
|
||||
]
|
||||
|
||||
# This tells uv where to look for 'agebd' during LOCAL dev work
|
||||
[tool.uv.sources]
|
||||
# Path is relative to where agebd package is deployed on hla
|
||||
# machines (see CI/CD in .gitea/workflows)
|
||||
agebd = { path = "../../../../../packages/{{ agebd_env }}/agebd", editable = true }
|
||||
|
||||
[tool.ruff]
|
||||
include = [
|
||||
"src/**/*.py",
|
||||
]
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
# use isort to sort imports
|
||||
extend-select = ["I"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ["agebd"]
|
||||
@@ -1,108 +0,0 @@
|
||||
from time import sleep
|
||||
|
||||
import typer
|
||||
from epics import dbr
|
||||
|
||||
from agebd.enums import LogLevel
|
||||
from agebd.pv import LocalPVLink
|
||||
from agebd.pv import PVLink as PV
|
||||
from agebd.runner import CallbackRunner
|
||||
from agebd.service.base import BaseService
|
||||
from agebd.service.pvs import BasePVs
|
||||
from agebd.utils import get_pv_class, init_logging, printgetversion
|
||||
|
||||
__version__ = printgetversion(__file__)
|
||||
|
||||
PV = get_pv_class()
|
||||
|
||||
|
||||
class PVs(BasePVs):
|
||||
# Option 1:
|
||||
## Service specific PVs from dedicated IOC
|
||||
my_pv1 = PV("MY_PV1")
|
||||
|
||||
## Service specific PVs from other IOCs
|
||||
# ...
|
||||
|
||||
def __init__(self, service_name: str, pv_factory):
|
||||
super().__init__(service_name, pv_factory)
|
||||
PV = pv_factory
|
||||
|
||||
# TODO: can we do this cleaner? Maybe mechanism for
|
||||
# settings initial values in dev mode (e.g. ini file)
|
||||
if isinstance(self.onoff, LocalPVLink):
|
||||
self.onoff.value = True
|
||||
|
||||
# Option 2:
|
||||
## Service specific PVs from dedicated IOC
|
||||
self.my_pv2 = PV("MY_PV2")
|
||||
|
||||
## Service specific PVs from other IOCs
|
||||
# ...
|
||||
|
||||
# TODO: class attribute names usually lowercase
|
||||
# usually it is advisable to trigger the mainloop of a service on changes of certain PVs:
|
||||
self.CallbackPV = PV("...", auto_monitor=dbr.DBE_VALUE)
|
||||
|
||||
|
||||
class Service(BaseService[PVs]):
|
||||
def __init__(
|
||||
self, name: str, pvs: PVs, version: str = __version__, sleep_interval: float = 0.1
|
||||
):
|
||||
super().__init__(name, pvs, version, sleep_interval)
|
||||
|
||||
# TODO: What is this for?
|
||||
self.path = "sls/bd/bin"
|
||||
|
||||
def update(self):
|
||||
# when callback is fired, this code will be executed
|
||||
if self.CallbackFired:
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
# here goes all the code that your service
|
||||
# is supposed to be running when the callback is fired
|
||||
sleep(1)
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
|
||||
# callback done
|
||||
self.CallbackFired = 0
|
||||
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
# here goes all the code that your service
|
||||
# is supposed to be running in any case, e.g.,
|
||||
# update some pvs/vals
|
||||
self.pvs.my_pv1.put("MY_PV1 value")
|
||||
self.pvs.my_pv2.put("MY_PV2 value")
|
||||
self.val1 = self.pvs.my_pv1.get()
|
||||
self.val2 = self.pvs.my_pv2.get()
|
||||
print(self.val1)
|
||||
print(self.val2)
|
||||
# maybe sleep to limit the update loop execution rate
|
||||
sleep(1)
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
|
||||
|
||||
def main(
|
||||
log_level: LogLevel = typer.Option(
|
||||
LogLevel.INFO,
|
||||
"--log-level",
|
||||
"-l",
|
||||
# Looks at the OS env variable first. If empty, falls back to "INFO"
|
||||
envvar="SLS_SERVICE_LOG_LEVEL",
|
||||
# help="Set log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
|
||||
case_sensitive=False,
|
||||
),
|
||||
):
|
||||
init_logging(log_level)
|
||||
service_name = ""
|
||||
pvs = PVs(service_name=service_name, pv_factory=PV)
|
||||
service = Service(name=service_name, pvs=pvs)
|
||||
runner = CallbackRunner(service=service)
|
||||
runner.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
||||
@@ -1,4 +0,0 @@
|
||||
file COOL-SERVICE.template {
|
||||
pattern { DEVICE }
|
||||
{ AGEBD-COOL-SERVICE }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
cpu_architecture: x86_64
|
||||
epics_version: 7.0.8
|
||||
ioc_host:
|
||||
ioc_port: 9999
|
||||
os: RHEL8
|
||||
os_id: rhel
|
||||
@@ -1 +0,0 @@
|
||||
epicsEnvSet("ENGINEER", "")
|
||||
@@ -1,16 +0,0 @@
|
||||
[Unit]
|
||||
Description=AGEBD-SERVICE-COOL-SERVICE
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Environment=AGEBD_ENV={{ agebd_env }}
|
||||
ExecStart=/sls/bd/hla/bin/start_service.sh 004 COOL-SERVICE
|
||||
estart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
|
||||
# systemctl --user daemon-reload
|
||||
# systemctl --user enable /sls/bd/bin/systemd/AGEBD-SERVICE-COOL-SERVICE.service
|
||||
# systemctl --user start AGEBD-SERVICE-COOL-SERVICE
|
||||
@@ -1,33 +0,0 @@
|
||||
[project]
|
||||
name = "agebd-cool-service"
|
||||
version = "0.1.0"
|
||||
description = "AGEBD-cool-service Service"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"agebd==1.2.0",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=8.4.2",
|
||||
"ruff>=0.15.20",
|
||||
]
|
||||
|
||||
# This tells uv where to look for 'agebd' during LOCAL dev work
|
||||
[tool.uv.sources]
|
||||
# Path is relative to where agebd package is deployed on hla
|
||||
# machines (see CI/CD in .gitea/workflows)
|
||||
agebd = { path = "../../../../../packages/{{ agebd_env }}/agebd", editable = true }
|
||||
|
||||
[tool.ruff]
|
||||
include = [
|
||||
"src/**/*.py",
|
||||
]
|
||||
line-length = 100
|
||||
|
||||
[tool.ruff.lint]
|
||||
# use isort to sort imports
|
||||
extend-select = ["I"]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ["agebd"]
|
||||
@@ -1,4 +0,0 @@
|
||||
file cool-service.template {
|
||||
pattern { DEVICE }
|
||||
{ AGEBD-cool-service }
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
cpu_architecture: x86_64
|
||||
epics_version: 7.0.8
|
||||
ioc_host:
|
||||
ioc_port: 9999
|
||||
os: RHEL8
|
||||
os_id: rhel
|
||||
@@ -1,27 +0,0 @@
|
||||
# This is a template for preaparing an IOC providing BD Service specific PVs
|
||||
# Access Security Groups:
|
||||
# DEFAULT - logt wenn EGU oder so veraendert werden
|
||||
# LOG - logt wenn neuer wert geschrieben wird
|
||||
# PROTECTED - verhindert versuchte caputs auf alle fields ausser VAL
|
||||
# READONLY - verhindert versuchte caputs und aktiviert caputlog
|
||||
# Input links can specify CA, CP, or CPP.
|
||||
# If the input link specifies CA, it will be forced to be a Channel Access link.
|
||||
# If the input link specifies CP, it will also be forced to be a Channel Access link; in addition, it will cause the record containing the input link to process whenever a monitor is posted, no matter what the record's SCAN field specifies.
|
||||
# If the input link specifies CPP, it means the same thing as CP, except that the record will be processed if and only if the record itself specifies passive in its SCAN field. Output links can specify CA, which will simply cause them to be Channel Access links.
|
||||
#
|
||||
|
||||
record(ao, "$(DEVICE):AO") {
|
||||
field(DESC, "Analog Output Record (ao)")
|
||||
field(ASG, "PROTECTED")
|
||||
field(VAL, "0")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
record(bo, "$(DEVICE):BO") {
|
||||
field(DESC, "Binary Output Record (bo)")
|
||||
field(ASG, "READONLY")
|
||||
field(ZSV, "MINOR")
|
||||
field(OSV, "NO_ALARM")
|
||||
field(VAL, "1")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
epicsEnvSet("ENGINEER", "")
|
||||
@@ -1 +0,0 @@
|
||||
# TODO
|
||||
@@ -1,16 +0,0 @@
|
||||
[Unit]
|
||||
Description=AGEBD-SERVICE-cool-service
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Environment=AGEBD_ENV={{ agebd_env }}
|
||||
ExecStart=/sls/bd/hla/bin/start_service.sh 1 cool-service
|
||||
estart=no
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
|
||||
# systemctl --user daemon-reload
|
||||
# systemctl --user enable /sls/bd/bin/systemd/AGEBD-SERVICE-cool-service.service
|
||||
# systemctl --user start AGEBD-SERVICE-cool-service
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "agebd-{{ service_name_lower }}"
|
||||
version = "0.1.0"
|
||||
description = "AGEBD-{{ service_name }} Service"
|
||||
description = "AGEBD-{{ service_name_upper }} Service"
|
||||
requires-python = ">=3.9"
|
||||
dependencies = [
|
||||
"agebd==1.2.0",
|
||||
+7
-4
@@ -1,8 +1,6 @@
|
||||
from time import sleep
|
||||
|
||||
import typer
|
||||
from epics import dbr
|
||||
|
||||
from agebd.enums import LogLevel
|
||||
from agebd.pv import LocalPVLink
|
||||
from agebd.pv import PVLink as PV
|
||||
@@ -10,6 +8,7 @@ from agebd.runner import CallbackRunner
|
||||
from agebd.service.base import BaseService
|
||||
from agebd.service.pvs import BasePVs
|
||||
from agebd.utils import get_pv_class, init_logging, printgetversion
|
||||
from epics import dbr
|
||||
|
||||
__version__ = printgetversion(__file__)
|
||||
|
||||
@@ -47,7 +46,11 @@ class PVs(BasePVs):
|
||||
|
||||
class Service(BaseService[PVs]):
|
||||
def __init__(
|
||||
self, name: str, pvs: PVs, version: str = __version__, sleep_interval: float = 0.1
|
||||
self,
|
||||
name: str,
|
||||
pvs: PVs,
|
||||
version: str = __version__,
|
||||
sleep_interval: float = 0.1,
|
||||
):
|
||||
super().__init__(name, pvs, version, sleep_interval)
|
||||
|
||||
@@ -97,7 +100,7 @@ def main(
|
||||
),
|
||||
):
|
||||
init_logging(log_level)
|
||||
service_name = "cool-service"
|
||||
service_name = "{{ service_name_upper }}"
|
||||
pvs = PVs(service_name=service_name, pv_factory=PV)
|
||||
service = Service(name=service_name, pvs=pvs)
|
||||
runner = CallbackRunner(service=service)
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
file {{ service_name_upper }}.template {
|
||||
pattern { DEVICE }
|
||||
{ AGEBD-{{ service_name_upper }} }
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
[Unit]
|
||||
Description=AGEBD-SERVICE-{{service_name}}
|
||||
Description=AGEBD-SERVICE-{{ service_name_upper }}
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Environment=AGEBD_ENV={{ '{{ agebd_env }}' }}
|
||||
ExecStart=/sls/bd/hla/bin/start_service.sh {{ service_id }} {{ service_name }}
|
||||
ExecStart=/sls/bd/hla/bin/start_service.sh {{ service_id }} {{ service_name_upper }}
|
||||
estart=no
|
||||
|
||||
[Install]
|
||||
@@ -12,5 +12,5 @@ WantedBy=default.target
|
||||
|
||||
# https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
|
||||
# systemctl --user daemon-reload
|
||||
# systemctl --user enable /sls/bd/bin/systemd/AGEBD-SERVICE-{{ service_name }}.service
|
||||
# systemctl --user start AGEBD-SERVICE-{{ service_name }}
|
||||
# systemctl --user enable /sls/bd/bin/systemd/AGEBD-SERVICE-{{ service_name_upper }}.service
|
||||
# systemctl --user start AGEBD-SERVICE-{{ service_name_upper }}
|
||||
-108
@@ -1,108 +0,0 @@
|
||||
from time import sleep
|
||||
|
||||
import typer
|
||||
from epics import dbr
|
||||
|
||||
from agebd.enums import LogLevel
|
||||
from agebd.pv import LocalPVLink
|
||||
from agebd.pv import PVLink as PV
|
||||
from agebd.runner import CallbackRunner
|
||||
from agebd.service.base import BaseService
|
||||
from agebd.service.pvs import BasePVs
|
||||
from agebd.utils import get_pv_class, init_logging, printgetversion
|
||||
|
||||
__version__ = printgetversion(__file__)
|
||||
|
||||
PV = get_pv_class()
|
||||
|
||||
|
||||
class PVs(BasePVs):
|
||||
# Option 1:
|
||||
## Service specific PVs from dedicated IOC
|
||||
my_pv1 = PV("MY_PV1")
|
||||
|
||||
## Service specific PVs from other IOCs
|
||||
# ...
|
||||
|
||||
def __init__(self, service_name: str, pv_factory):
|
||||
super().__init__(service_name, pv_factory)
|
||||
PV = pv_factory
|
||||
|
||||
# TODO: can we do this cleaner? Maybe mechanism for
|
||||
# settings initial values in dev mode (e.g. ini file)
|
||||
if isinstance(self.onoff, LocalPVLink):
|
||||
self.onoff.value = True
|
||||
|
||||
# Option 2:
|
||||
## Service specific PVs from dedicated IOC
|
||||
self.my_pv2 = PV("MY_PV2")
|
||||
|
||||
## Service specific PVs from other IOCs
|
||||
# ...
|
||||
|
||||
# TODO: class attribute names usually lowercase
|
||||
# usually it is advisable to trigger the mainloop of a service on changes of certain PVs:
|
||||
self.CallbackPV = PV("...", auto_monitor=dbr.DBE_VALUE)
|
||||
|
||||
|
||||
class Service(BaseService[PVs]):
|
||||
def __init__(
|
||||
self, name: str, pvs: PVs, version: str = __version__, sleep_interval: float = 0.1
|
||||
):
|
||||
super().__init__(name, pvs, version, sleep_interval)
|
||||
|
||||
# TODO: What is this for?
|
||||
self.path = "sls/bd/bin"
|
||||
|
||||
def update(self):
|
||||
# when callback is fired, this code will be executed
|
||||
if self.CallbackFired:
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
# here goes all the code that your service
|
||||
# is supposed to be running when the callback is fired
|
||||
sleep(1)
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
|
||||
# callback done
|
||||
self.CallbackFired = 0
|
||||
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
# here goes all the code that your service
|
||||
# is supposed to be running in any case, e.g.,
|
||||
# update some pvs/vals
|
||||
self.pvs.my_pv1.put("MY_PV1 value")
|
||||
self.pvs.my_pv2.put("MY_PV2 value")
|
||||
self.val1 = self.pvs.my_pv1.get()
|
||||
self.val2 = self.pvs.my_pv2.get()
|
||||
print(self.val1)
|
||||
print(self.val2)
|
||||
# maybe sleep to limit the update loop execution rate
|
||||
sleep(1)
|
||||
#######################################################################################
|
||||
#######################################################################################
|
||||
|
||||
|
||||
def main(
|
||||
log_level: LogLevel = typer.Option(
|
||||
LogLevel.INFO,
|
||||
"--log-level",
|
||||
"-l",
|
||||
# Looks at the OS env variable first. If empty, falls back to "INFO"
|
||||
envvar="SLS_SERVICE_LOG_LEVEL",
|
||||
# help="Set log level: DEBUG, INFO, WARNING, ERROR, CRITICAL",
|
||||
case_sensitive=False,
|
||||
),
|
||||
):
|
||||
init_logging(log_level)
|
||||
service_name = "{{service_name}}"
|
||||
pvs = PVs(service_name=service_name, pv_factory=PV)
|
||||
service = Service(name=service_name, pvs=pvs)
|
||||
runner = CallbackRunner(service=service)
|
||||
runner.start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
typer.run(main)
|
||||
-4
@@ -1,4 +0,0 @@
|
||||
file {{ service_name }}.template {
|
||||
pattern { DEVICE }
|
||||
{ AGEBD-{{ service_name }} }
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
# This is a template for preaparing an IOC providing BD Service specific PVs
|
||||
# Access Security Groups:
|
||||
# DEFAULT - logt wenn EGU oder so veraendert werden
|
||||
# LOG - logt wenn neuer wert geschrieben wird
|
||||
# PROTECTED - verhindert versuchte caputs auf alle fields ausser VAL
|
||||
# READONLY - verhindert versuchte caputs und aktiviert caputlog
|
||||
# Input links can specify CA, CP, or CPP.
|
||||
# If the input link specifies CA, it will be forced to be a Channel Access link.
|
||||
# If the input link specifies CP, it will also be forced to be a Channel Access link; in addition, it will cause the record containing the input link to process whenever a monitor is posted, no matter what the record's SCAN field specifies.
|
||||
# If the input link specifies CPP, it means the same thing as CP, except that the record will be processed if and only if the record itself specifies passive in its SCAN field. Output links can specify CA, which will simply cause them to be Channel Access links.
|
||||
#
|
||||
|
||||
record(ao, "$(DEVICE):AO") {
|
||||
field(DESC, "Analog Output Record (ao)")
|
||||
field(ASG, "PROTECTED")
|
||||
field(VAL, "0")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
record(bo, "$(DEVICE):BO") {
|
||||
field(DESC, "Binary Output Record (bo)")
|
||||
field(ASG, "READONLY")
|
||||
field(ZSV, "MINOR")
|
||||
field(OSV, "NO_ALARM")
|
||||
field(VAL, "1")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
# TODO
|
||||
Reference in New Issue
Block a user