epics-base / p4p

Python bindings for the PVAccess network client and server.
BSD 3-Clause "New" or "Revised" License
27 stars 38 forks source link

Flexible handler for NTScalar standard optional fields #149

Open Monarda opened 3 months ago

Monarda commented 3 months ago

The file nthandlers.py implements the logic required for NTScalar control, valueAlarm, and timeStamp fields. A put or post will be evaluated against those structures if present, e.g. if control.limitHigh is set then the value of the PV will not be allowed to exceed that value, or if a value below valueAlarm.lowAlarmLimit is set then alarm.severity will be set to valueAlarm.lowAlarmSeverity.

The included example code shows this in practice:

pv = SharedPV(nt=NTScalar('d', control=True, valueAlarm=True),
              handler=NTScalarRulesHandler(),
              initial=12.0)
pv.post({'control.limitHigh': 6,
         'valueAlarm.active': True, 'valueAlarm.lowAlarmLimit': 1, 'valueAlarm.lowAlarmSeverity':2})

Server.forever(providers=[{
    'demo:pv:name':pv,
}])

and using pvput we see the expected results:

> ./pvput demo:pv:name 12
Old : 2024-08-04 18:44:07.781  4
New : 2024-08-04 18:44:12.279  6
> ./pvput demo:pv:name 0
Old : 2024-08-04 18:44:12.279  6
New : 2024-08-04 18:44:14.502  0 MAJOR lowAlarm

The code uses two orderedDicts to construct a list of rules. One set of rules are applied to onFirstConnect and are used to ensure the PVs are immediately in the correct state, e.g. control limits applied before first connection is evaluated. The second set of rules are applied to each post (these have the prior and ServerOperation state to consider). In practice the two sets of rules share a considerable amount of code. A developer may interact with the orderedDicts to override default behaviour or add additional user-specified behaviour.

Does this seem useful? If so, in generalt terms, is this implementation a sensible way of supplying this functionality?

I thought it made sense to check if was desired before extending to other Normative Types or implementing tests.

Monarda commented 3 months ago

I forgot to add this has only been lightly tested with Python 3.8 and Python 3.11.