Acting on the device
Example module: helloindiactions.
In Creating properties dynamically, the action button modified the module’s internal state (hellodyn). Here, the action actually modifies something on the device — the device itself persists it, not the module.
HelloIndiActions::HelloIndiActions(...)
: IndiModule(...)
{
giveMeADevice("device", "Device", INDI::BaseDevice::GENERAL_INTERFACE);
giveMeAnActions();
OST::ElementBool *saveconfig = new OST::ElementBool("saveconfig", "Save device config", "1", "");
saveconfig->setDirectEdit(true);
getProperty("actions")->addElt(saveconfig);
}giveMeAnActions() builds the actions property (empty at first); addElt() adds the saveconfig element to it, in C++, as in Creating properties dynamically — this chapter changes nothing about how a property is built, only what happens when it is triggered.
void HelloIndiActions::onExternalEvent(OST::ExtEvent event)
{
if (event.ev != OST::ExtEvType::SV || event.prpkey != "actions" || event.eltkey != "saveconfig") return;
sendModNewSwitch(getString("devices", "device"), "CONFIG_PROCESS", "CONFIG_SAVE", ISS_ON);
getEltBool("actions", "saveconfig")->setValue(false, true);
}CONFIG_PROCESS/CONFIG_SAVE is a standard INDI switch, present on every driver (save the current configuration) — which makes this example testable against any connected device, without depending on a feature specific to one particular simulator.
These helpers only write one element at a time: they fetch the property as currently known on the client side, change the value of the targeted element, then send back the whole vector — the other elements go out with their last known value, not necessarily 0, not necessarily what the driver expects.
Concrete example: sending a guide pulse to a mount. TELESCOPE_TIMED_GUIDE_NS has two elements, TIMED_GUIDE_N and TIMED_GUIDE_S — you only ever pulse in one direction at a time, so the driver expects to receive both values on every send, one of them explicitly set to 0. By only writing TIMED_GUIDE_N via sendModNewNumber(), TIMED_GUIDE_S goes out with its last known value — potentially nonzero, which the driver may simply ignore or misinterpret.
In this kind of case, it’s better to drop straight down to the INDI::BaseClient level (see the overview: an IndiModule is a real INDI client): build the full INDI::PropertyNumber yourself, explicitly set every element, then call sendNewNumber() directly — rather than trusting a helper designed for the simple case of a property with a single relevant element.