Keep the Property-States updated

When developing an application which is using the LaRoomy Api, it is important to understand that the interface is not only a tool to achieve data transmission between your application and the LaRoomy App, it is also the data-holder for the current hardware states.

For example:
When a Switch property is added and the execution of the switch should turn on a light which is done by setting a pin high (or low if the switch is turned off), then the switch is bound to the pin. If the switch is turned ON or OFF inside of the app and a state update is received, the pin must be set HIGH or LOW, respectively. On the other way around, if the pin is set to HIGH/LOW due to another reason (e.g. hardware switch or low battery), the internal state of the LaRoomy Api must be updated, even though the device is not connected!
If this is not done, the next time the app will be connected, an incorrect state will be transmitted, since the internal state is not updated and the Api transmits the outdated value. This breaks the Api-Hardware state alignment. It is your responsibility to make sure the state of the property in the Api is updated every time the hardware state changes. This applies to all properties that have states that can change or at least those that are bound to a hardware state.

Do not call state update methods periodically without a reason. Only update a state when the state has actually changed. Note that when the device is connected and the state is updated, an update transmission is sent. Successive state updates that are not necessary will flood the line with unnecessary transmissions.

How it works


Let's proceed with the above mentioned switch example.

At first some predefinitions: a pin is needed for output (LED) and one for input (hardware button).

  		
// define the pin names
#define LED_1 2
#define HBUTTON_1 4

#define SWITCH_ID 1
  	

In the handler for the remote events the output pin is set in relation to the property state.

  		  
// define the callback for the remote app-user events
class RemoteEvents : public ILaroomyAppCallback
{
public:
    // receive switch state changes
    void onSwitchStateChanged(cID switchID, bool newState) override
    {
        if (switchID == SWITCH_ID)
        {
            // set the state of the pin
            if (newState)
            {
                digitalWrite(LED_1, HIGH);
            }
            else
            {
                digitalWrite(LED_1, LOW);
            }
        }
    }
};
  	

In device setup the pins are configured and set. The output pin is set to LOW. The switch property is added and it's initial state is set to false in relation to the LED_1 pin state.

  		    
void setup()
{
    // put your setup code here, to run once:

    pinMode(LED_1, OUTPUT);
    pinMode(HBUTTON_1, INPUT); 
    digitalWrite(LED_1, LOW);  // pin intially off
 
    // begin
    LaRoomyApi.begin();

    // set the bluetooth name
    LaRoomyApi.setBluetoothName("My Switch");

    // set the callback handler for remote events
    LaRoomyApi.setCallbackInterface(
        dynamic_cast<ILaroomyAppCallback *>(
            new RemoteEvents()));

    // declare the switch property
    Switch sw1;
    sw1.imageID = LaRoomyImages::CEILING_LAMP_007;
    sw1.switchDescription = "LED 1";
    sw1.switchID = MY_FIRST_SWITCH_ID;
    sw1.switchState = false;			// state initially off
    
    // add the switch property
	LaRoomyApi.addDeviceProperty(sw1);    

    // on the end, call run to apply the setup and start bluetooth advertising
    LaRoomyApi.run();
}
  	

Now, when the program is running and the hardware button is pressed, the output on the LED_1 pin is toggled. So the hardware state changes and this must be reflected to the Api through calling the respective property-state update method.

  		    
void loop()
{
    // put your main code here, to run repeatedly:

    // the 'onLoop' method must be implemented here to permanently check for incoming transmissions
    LaRoomyApi.onLoop(); 

    // hardware button is pressed
    if (digitalRead(HBUTTON_1) == LOW)
    {
        delay(10);

        // first get the current internal state
        auto firstSwitchState =
            (LaRoomyApi.getSimplePropertyState(SWITCH_ID) > 0)
            ? true : false;
            
        if (firstSwitchState)
        {
            // the state was ON, so set it to OFF and update
            digitalWrite(LED_1, LOW);
            LaRoomyApi.updateSimplePropertyState(SWITCH_ID, OFF);
        }
        else
        {
            // the state was OFF, so set it to ON and update
            digitalWrite(LED_1, HIGH);
            LaRoomyApi.updateSimplePropertyState(SWITCH_ID, ON);
        }

        while (digitalRead(HBUTTON_1) == LOW)
            ;
        delay(50);
    }

}