API Version for 8bit Systems
If a program for a small microcontroller with 8bit architecture should be created, the common LaRoomy Api libraries are not suitable since they are for 32bit architectures or higher. So a minimized version of the LaRoomy Api was created. It is written in plain C and is not platform specific so it could be used for a wide amount of controller types with included or external bluetooth capabilities.
The minimized library with schematic and board data and example projects are available here.
To get an overview of all functions and facilities of the API take a look at the base header file. The following example instructions demonstrate how a implementation of the minimized API could be achieved.
Implementation Guideline
• Define unique ID's for all properties
Defining identification constants make is easy to identify a property to access, update and work with it later in the code.
// define the property ID's
#define PROPERTY_TOGGLE_BUTTON 1
#define PROPERTY_BATTERY_LEVEL_INDICATOR 2
#define PROPERTY_TIME_SELECTOR 3
Do not use zero as an ID, since this is in invalid value for the identification of a property. And do not use an ID more than once.
• Create global device property struct parameter as data-holder for the property data
Even though the properties will be added to the LaRoomy Api later, there is no dynamic memory allocation like in the higher level libraries, because on a system with very limited resources, it makes no sense to copy the data. The memory section which is to contain the data for a property must be provided as global parameter which can be accessed through the hole lifetime of the program. The api takes only a reference to the property struct.
// create the property elements
DEVICE_PROPERTY toggleButton ;
DEVICE_PROPERTY batteryLevelIndicator ;
DEVICE_PROPERTY timeSelector ;
• Create global struct parameter for the complex states of all properties
If device properties with complex state type are used, the respective complex property state struct must be also created as data-holder due to the reason explained above.
// create the complex property state for the time-selector created above
TIME_SELECTOR_STATE timeSelectorState ;
• Declare a callback function for all callbacks that must be used
// this function will be used by the api to report remote events
void remoteCallback(uint8_t propertyID , uint8_t eventID );
• Declare a function that handles the data output to the Bluetooth data gateway
// this function must be implemented later
void sendBLEData(const char* data );
• Register the callback(s)
// set the callback to catch remote events
// every time the user interacts with a property
// in the laroomy app, this callback will be invoked
registerRemoteCallback(remoteCallback );
• Register the output gateway function
// set the usart output gateway for the laroomy api
// - the internal transmission control will use this function to send data
setOutGateway(sendBLEData );
• Initialize all property structs
Before the property structs are added to the LaRoomy Api, they must be initialized with valid values. This could be done by using the provided init function
// call the init function to validate the property structs
initDevicePropertyStruct(&toggleButton );
initDevicePropertyStruct(&batteryLevelIndicator );
initDevicePropertyStruct(&timeSelector );
• Set the property data
This is the point where the property is defined. The values determine the appearence of the property in the app and how the property works.
// set the button data
toggleButton .ID = PROPERTY_TOGGLE_BUTTON ; // unique ID
toggleButton .type = PTYPE_BUTTON ; // type of the property
toggleButton .imageID = LIGHT_BULB_004 ; // image of the property
// use this method to set the property descriptor
setPropertyDescriptor(&toggleButton , "Test LED;;Toggle"); // dual descriptor: element-text and button-text
// add the button
addDeviceProperty(&toggleButton);
// add other properties ...
• Set the initial state data for the complex state of a property (if used)
For all properties of complex type, a data holder struct must be defined and added to the api. If no properties of complex type are used the step can be skipped. Before adding a state it should be initialized with default values or with saved values (if the previous setup was saved permanently before).
// add the state for the time selector
// set default values
timeSelectorState .hour = 20;
timeSelectorState .minute = 0;
// add it
addTimeSelectorStateForProperty(PROPERTY_TIME_SELECTOR , &timeSelectorState );
The api must be provided with an input and output gateway to receive and send bluetooth data. This is critical, otherwise the api cannot work correctly.
• Handle incoming data
When the program is running, make sure to forward all received bluetooth data to the api to process it.
// check if data was received on your bluetooth implementation
char* data = fetchBLEData();
if(data != NULL)
{
// if data was received, pass it to the input function of the api
onDataReceived(data );
}
• Handle outgoing data
Here the previously declared output gateway function must be defined to enable the api to send data. A reference to the function was passed to the api earlier.
// this function will be invoked by the LaRoomy Api to send data
void sendBLEData(const char* data )
{
// TODO: forward the data to the bluetooth output
}
• Implement the remote callback to receive events
When the program is running, make sure to forward all received bluetooth data to the api to process it.
// receive remote events
void remoteCallback(uint8_t propertyID , uint8_t eventID )
{
// catch the event
switch (eventID )
{
case REVT_BUTTON_PRESSED :
// make sure to address the correct property
if (propertyID == PROPERTY_TOGGLE_BUTTON )
{
// toggle led
}
break;
case REVT_TIME_SELECTOR_STATE_CHANGED :
if(propertID == PROPERTY_TIME_SELECTOR )
{
// the app user has selected a new time
}
break;
case REVT_PROPERTY_LOADING_FROM_DEVICE_COMPLETE :
// when properties are loaded, send a time request to save the current time
// to the time keeper
sendTimeRequest();
break;
case REVT_PROPERTY_LOADING_FROM_CACHE_COMPLETE :
// when properties are loaded, send a time request to save the current time
// to the RTC
sendTimeRequest();
break;
case REVT_TIME_REQUEST_RESPONSE :
{
uint8_t hours ;
uint8_t minutes ;
uint8_t seconds ;
// fetch time data
fetchTimeResponseData(&hours , &minutes , &seconds );
// setup rtc
RTC .setTime(hours , minutes , seconds );
}
break;
default:
break;
}
}
To take a look at a complete example, visit the Examples section of the GitHub repository.