COVID-19 vaccinations happen at very large areas such as sports stadium, school grounds, or any covered open spaces. Before using the COVID-19 vaccines, are stored in vaccine carrier cold boxes.
Some COVID-19 vaccines such as Pfizer BionTech and Moderna requires to be stored at a specific temperature range before using.
- Pfizer BionTech COVID-19 Vaccine: 2°C to 25°C (36°F to 77°F)
- Moderna COVID-19 Vaccine: 8°C to 25°C (46°F to 77°F)
COVID-19 vaccine carrier cold boxes containing COVID-19 vaccines at large vaccination sites could be left unattended and unknowingly have been at a temperature range outside of the recommended, which could lower it's effectivity against COVID-19 virus.
Solution:Remote monitor the COVID-19 vaccine carrier cold boxes temperature at large vaccination sites using AWS IOT EduKit and Sub 1-Ghz Sensor Network.
TexasInstrumentsSub 1-Ghz sensor network:
Benefits of usingSub 1-Ghz sensor network:
- Communicate at longer range.
- Sub 1-Ghz have much better material penetration capability compared to 2.4 Ghz.
- Co-existence with other frequencies.
- Connect 200+ sensor nodes to 1 collector.
- Sensor node and collector boards can operate in micro amp range.
Modifying the TISub 1-Ghz sensor network example programs:
Benefits of Bluetooth connectivity at sensor node:- Firmware Download over Bluetooth (OAD or OTA).
- Provision credentials from collector to enable communication between sensor node and collector.
- Change sensor node values such as "Container ID" and "Vaccine Name".
AWSIOT EduKit PortC UART connection to CC1352R Launchpad:
- Port C GND (Black Wire) -> CC1352R Launchpad GND.
- Port C 3V (Red Wire) -> CC1352R Launchpad 3.3V
- Port C UART TX (White Wire) -> CC1352R Launchpad DIO12 UART RX
- Port C UART RX (Yellow Wire) -> CC1352R Launchpad DIO13 UART TX
Ideally, the sensor node antenna should be outside the container.
AWS IOT EduKit Port C UART initalization:void app_main()
{
Core2ForAWS_Init();
esp_err_t err = Core2ForAWS_Port_PinMode(PORT_C_UART_TX_PIN, UART);
if (err == ESP_OK){
Core2ForAWS_Port_C_UART_Begin(115200);
xTaskCreate(uart_rx_task, "uart_rx", 1024*2, NULL, configMAX_PRIORITIES, NULL);
}
}
AWS IOT EduKit receiving data from Port C UART:/*! UART Data message: sent from the collector to AWS IOT EduKit */
typedef struct _uart_sensormsg_t
{
uint16_t nodecnt;
uint16_t containerid;
uint8_t vaccinename[20];
uint16_t temp;
uint16_t battval;
}uart_sensorMsg_t;
uart_sensorMsg_t uartmsg;
static void uart_rx_task(void *arg){
int rxBytes;
uint8_t *data = heap_caps_malloc(UART_RX_BUF_SIZE, MALLOC_CAP_SPIRAM);
while (1) {
rxBytes = Core2ForAWS_Port_C_UART_Receive(data);
if (rxBytes > 0) {
memcpy(&uartmsg, data, sizeof(uartmsg));
}
vTaskDelay(pdMS_TO_TICKS(100));
}
free(data); // Free memory from external RAM
}
UARTdata messagesent from collector to AWS IOT EduKit:
- Node Count - Number of sensor nodes connected to collector.
- Container ID - Vaccine carrier cold box ID. Set at sensor node using Bluetooth connection.
- Vaccine Name - Name of COVID-19 vaccines in vaccine carrier cold box. Set at sensor node using Bluetooth Connection.
- Temperature - Sensor node HDC2080 temperature data.
- Battery Value - Sensor node battery value in millivolts.
static void publisher(AWS_IoT_Client *client, char *base_topic, uint16_t base_topic_len){
IoT_Publish_Message_Params paramsQOS0;
paramsQOS0.qos = QOS0;
paramsQOS0.isRetained = 0;
char cdate[100] = {0,};
BM8563_GetTime(&date);
sprintf(cdate,"Date: %d-%02d-%02d Time: %02d:%02d:%02d", date.year, date.month, date.day,
date.hour, date.minute, date.second);
dtemp = (double)((uartmsg.temp * CELSIUS_PER_LSB) - 40);
dtemp = f_round(dtemp, 2);
// Get state of the FreeRTOS task, "blinkTask", using it's task handle.
eTaskState blinkState = eTaskGetState(xBlink);
if((dtemp < mintemp) || (dtemp > maxtemp)){
if (blinkState == eSuspended){
vTaskResume(xBlink);
}
}
else if((dtemp >= mintemp) && (dtemp <= maxtemp)){
vTaskSuspend(xBlink);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0x000000);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0x000000);
Core2ForAWS_Sk6812_Show();
}
cJSON *payload = cJSON_CreateObject();
cJSON *date_time = cJSON_CreateString((const char*)cdate);
cJSON *container_id = cJSON_CreateNumber(uartmsg.containerid);
cJSON *vaccine_name = cJSON_CreateString((const char *)uartmsg.vaccinename);
cJSON *temperature = cJSON_CreateNumber(dtemp);
cJSON *batt_value = cJSON_CreateNumber(uartmsg.battval);
cJSON_AddItemToObject(payload, "timestamp", date_time);
cJSON_AddItemToObject(payload, "container_id", container_id);
cJSON_AddItemToObject(payload, "vaccine_name", vaccine_name);
cJSON_AddItemToObject(payload, "temperature", temperature);
cJSON_AddItemToObject(payload, "battery_value", batt_value);
const char *JSONPayload = cJSON_Print(payload);
paramsQOS0.payload = (void *) JSONPayload;
paramsQOS0.payloadLen = strlen(JSONPayload);
// Publish and ignore if "ack" was received or from AWS IoT Core
IoT_Error_t rc = aws_iot_mqtt_publish(client, base_topic, base_topic_len, ¶msQOS0);
if (rc != SUCCESS){
ESP_LOGE(TAG, "Publish QOS0 error %i", rc);
rc = SUCCESS;
}
ui_textarea_add("%s", (char *)JSONPayload, paramsQOS0.payloadLen);
cJSON_Delete(payload);
}
After this video blog, we added timestamp as part of the MQTT message sent to AWS IOT.
AWS IOT MQTT Test received message payload:Blinking the ledbars:
To blink the led bars, we re-use the "blink_task" at Blinky Hello World example program.
xTaskCreatePinnedToCore(&blink_task, "blink_task", 4096 * 1, NULL, 2, &xBlink, 1);
If any sensor node temperature goes beyond the set minimum and maximum temperature range the led bars will alternately blink red.
- Default Minimum Temperature: 2°C
- Default Maximum Temperature: 25°C
static void publisher(AWS_IoT_Client *client, char *base_topic, uint16_t base_topic_len){
IoT_Publish_Message_Params paramsQOS0;
paramsQOS0.qos = QOS0;
paramsQOS0.isRetained = 0;
dtemp = (double)((uartmsg.temp * CELSIUS_PER_LSB) - 40);
dtemp = f_round(dtemp, 2);
// Get state of the FreeRTOS task, "blinkTask", using it's task handle.
eTaskState blinkState = eTaskGetState(xBlink);
if((dtemp < mintemp) || (dtemp > maxtemp)){
if (blinkState == eSuspended){
vTaskResume(xBlink);
}
}
else if((dtemp >= mintemp) && (dtemp <= maxtemp)){
vTaskSuspend(xBlink);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_LEFT, 0x000000);
Core2ForAWS_Sk6812_SetSideColor(SK6812_SIDE_RIGHT, 0x000000);
Core2ForAWS_Sk6812_Show();
}
Changing the minimum and maximum temperature range:To change the minimum and maximum temperature range, we publish from AWS IOT this message payload format to topic "temprange".
{
"min": 5,
"max": 20
}
Changing the date and time:To change the date and time, we publish from AWS IOT this message payload format to topic "date".
{
"year": 2021,
"month": 0,
"day" : 0,
"hour" : 0,
"minutes" : 0,
"seconds" : 0
}
Parsing the received message payloadat AWS IOT EduKit:
void iot_subscribe_callback_handler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen,
IoT_Publish_Message_Params *params, void *pData) {
ESP_LOGI(TAG, "Subscribe callback");
ESP_LOGI(TAG, "%.*s\t%.*s", topicNameLen, topicName, (int) params->payloadLen, (char *)params->payload);
if (strstr(topicName, "/temprange") != NULL) {
cJSON *item;
cJSON *root = cJSON_Parse((char *)params->payload);
item = cJSON_GetObjectItem(root, "min");
mintemp = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "max");
maxtemp = *(&(item->valueint));
cJSON_Delete(root);
ui_textarea_add_number("\nnew min temp: %d\n", mintemp, sizeof(int));
ui_textarea_add_number("new max temp: %d\n", maxtemp, sizeof(int));
}
else if (strstr(topicName, "/date") != NULL) {
cJSON *item;
cJSON *root = cJSON_Parse((char *)params->payload);
item = cJSON_GetObjectItem(root, "year");
date.year = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "month");
date.month = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "day");
date.day = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "hour");
date.hour = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "minutes");
date.minute = *(&(item->valueint));
item = cJSON_GetObjectItem(root, "seconds");
date.second = *(&(item->valueint));
cJSON_Delete(root);
BM8563_SetTime(&date);
ui_textarea_add("\nNew date set\n", NULL, 0);
}
}
Rule to send data to AWSDynamoDB:
Following the Store device data DynamoDB table tutorial, we create a rule that sends message data to DynamoDB table.
AWSDynamoDB Table:
Comments