Heartbeats
OKE systems must send periodic OKMs that contain the operational status of the system. The CWL will automatically invoke CWPortGenHeartbeatCB() once every minute to allow the application code to generate its application specific heartbeat message. The heartbeat message must be valid JSON.
CWPortGenHeartbeatCB() is an MJSON printer function invoked under the context of a MJPrintf() call triggered by the library. Implementors must use MJPrintf() calls within the context of CWPortGenHeartbeatCB()to generate the heartbeat message. The function must return the total number of new bytes written to the message. Implementors will have either 300 or 800 (default) bytes of buffer space for generating each heartbeat message depending on the CWL configuration.
CW_PORT_IS_SMALL_MSG_ENABLED = 1 in cwport.h can be used to configure the CWL for 300 byte SRAM hardware implementation.
Implementors can cause the callback to be invoked additional times when more than one heartbeat OKM must be generated each minute or when a critical state change occurs. This is done by calling CWCmdScheduleHeartbeat().
The last heartbeat message per minute interval should not invoke CWCmdScheduleHeartbeat() because that will cause continuous heartbeat generation.
Heartbeat Throttling
The CWL has added a throttling mechanism for heartbeats that prevents the generation of more than CW_PORT_MAX_HEARTBEATS_PER_MIN per minute. Continuous generation of heartbeat messages clogs up the outbound store and forward queues and the bandwidth to the OKC with highly redundant information. Additionally, it can starve out other CWL message generation.
CW_PORT_MAX_HEARTBEATS_PER_MIN is defined in cwport.h and the default is 15 which should be more than enough for most applications such that they are never throttled.
If a throttling event occurs the CWL will report additional diagnostics to the OKC so that the condition is recorded. When the next one-minute period begins, the application will be allowed to send another set of heartbeats.
Common causes of excessive heartbeat generation includes calling CWCmdScheduleHeartbeat() every time CWPortGenHeartbeatCB() is invoked and calling CWCmdScheduleHeartbeat()continuously while the equipment is in a fault state when the desired behavior is to send a single set of heartbeats after entering the fault state.
Partitioning Heartbeats
There is a 1000 total byte limit for each OKM including required overhead added by the CWL and NULL terminator. Implementors must target a maximum heartbeat payload size of either 300 or 800 bytes. This will adequately account for overhead and some margin for future protocol changes. Many systems will be able to encode all the required heartbeat data in 800 bytes.
However, some systems may have more than 800 bytes of heartbeat data, and/or may be organized in such a way that logically organizing data in distinct heartbeats is convenient. For example, a modular oven system, may send a separate heartbeat for each cabinet.
From an efficiency perspective it is better to have fewer, larger heartbeats, rather than many, smaller heartbeats, since the overhead of each message is constant.
OKM Formatting
It is valid for JSON strings to include whitespace and line breaks. This formatting does not alter the meaning of a JSON message. However, it does unnecessarily consume additional memory and network bandwidth. Therefore, implementors should not include whitespace or line breaks in their generated messages.
Rate Limiting
Heartbeats should only be generated once per minute. It is best to report faults and other events that occur between heartbeats as ascending counters. These counters can be reset to 0 on a restart. The OKC can determine the type and number of faults that occurred between two heartbeats. The OKE may generate additional heartbeats when certain events occur, but this is not encouraged. However, if a requirement exists to do so then the OKE must implement a rate limiting mechanism to prevent the CWM store and forward queue from being filled with OKMs that consume storage and network resources and limit the ability to diagnose problems by delaying delivery of newer OKMs to the OKC.
Every OKE must be a good OpenKitchen citizen and try to use the minimum resources necessary when sending heartbeats. By doing so the entire OpenKitchen system will work better for our customers.
Pseudocode Example
This example is from the Window port. It shows a simple scenario where the application code generates two heartbeat message each minute. This is a contrived example since all the data could have fit into a single heartbeat. When hbState is zero the callback prints the door count data, requests an additional heartbeat by calling CWCmdScheduleHeartbeat() and changes hbState to 1. The CWL will invoke the callback a second time after the first one is sent. Since hbState is one the temp data is reported, and the state is set back to 0. It does not call CWMsgTxHeartbeat() again since all the heartbeats have been sent for this cycle.
Int32_t CWPortGenHeartbeatCB(MJBuffer_t* mb, va_list* ap)
{
int total = 0;
static uint8_t hbState;
static uint32_t appcount;
switch (hbState)
{
case 0:
total += MJPrintf(mb, "%Q:%u", "door", appcount);
appcount++;
CWCmdScheduleHeartbeat();
hbState = 1;
break;
default:
total += MJPrintf(mb, "%Q:%u", "temp", 350 + appcount % 10);
hbState = 0;
break;
}
return total;
}
The following are messages generated by the example code.
{"_dst":["OKC"],"_src":["0011223344556677"],"_cmd":"wr","_id":24,"_ts":"2019-12-06T12:06:00","_crc":"48D7","_pld":{"_hbt":{"door":8}}}
{"_dst":["OKC"],"_src":["0011223344556677"],"_cmd":"wr","_id":25,"_ts":"2019-12-06T12:06:00","_crc":"6949","_pld":{"_hbt":{"temp":359}}}
The CWPortGenHeartbeatCB() function only is responsible for the "door":8 and "temp":359 portions of the messages. The rest of the JSON is automatically generated by the library.