It is not clear to me if all devices are unique or if there are also several instances of the same device. But in both cases, I usually start by defining a protocol for the devices interface. In this case, one of the main predicates would be init/0
:
:- protocol(device).
:- public(init/0).
:- end_protocol.
If a device is unique, it can be represented by a prototype that implements the device
protocol. For example:
:- object('5c:cf:7f:00:1c:87', implements(device)).
init :-
this(MAC), % this goal is inlined
neopixel::(
setspeed(MAC, 5000),
setbrightness(MAC, 50),
mode(MAC, 14),
cmd(MAC, 'start')
).
:- end_object.
Assuming that all neopixel
public predicates take a MAC address would allow us to simplify to:
:- object('5c:cf:7f:00:1c:87', implements(device)).
init :-
this(MAC), % this goal is inlined
neopixel(MAC)::(
setspeed(5000),
setbrightness(50),
mode(14),
cmd('start')
).
:- end_object.
If there are several instances of the same device, let’s say, lamp
, that only differ on the parameters, I would use instead a parametric object:
:- object(lamp(_MAC_,_Speed_,_Brightness_,_Mode_,_Cmd_), implements(device)).
init :-
neopixel(_MAC_)::(
setspeed(_Speed_),
setbrightness(_Brightness_),
mode(_Mode_),
cmd(_Cmd_)
).
:- end_object.
And then define a Prolog table with facts (parametric object proxies) for each lamp:
% lamp(Mac, Speed, Brightness, Mode, Cmd)
lamp('5c:cf:7f:00:1c:87', 5000, 50, 14, 'start').
lamp('cc:50:e3:17:6a:1e', 7500, 35, 42, 'start').
...
I can then e.g. initialize all lamps by calling:
?- {lamp(_,_,_,_,_)}::init, fail; true.
Alternatively:
?- forall(lamp(MAC,S,B,M,C), lamp(MAC,S,B,M,C)::init).
We can also initialize just a specific device given its MAC address:
?- {lamp('5c:cf:7f:00:1c:87',_,_,_,_)}::init.
If multiple devices share all but a few of the parameterizations, we can also due for example:
:- object(lamp_mode(MAC, Mode), extends(lamp(MAC,5000,50,Mode,'start')).
:- end_object.
lamp_mode('5c:cf:7f:00:1c:87', 14).
lamp_mode('cc:50:e3:17:6a:1e', 42).
...
By now, you can see there are several common points between this structured solution and other suggestions on this discussion thread. Some of the advantages of this structured approach is that it easily scales to a large number of devices where we can have a mix of unique devices and multiple instances of the same devices with just different parameterizations and taxonomies of devices where features are inherited.