Hacking Izon Cameras and using Azure IoT Edge

After Izon announced that they were closing down their services (leaving the cameras I already owned useless), I decided to turn them into something useful using Azure. First let me list some resources:

Use the Will it hack link to get access to the mobileye website and verify that the Izon device is still streaming and still working. If it is working, you are already done with edits to the device unless you would like to change the passwords (which you should).

Our goals are as follows:

  • Process the video feed from the Izon camera (we will cheat this early on and only use the image feed)
    • Check for motion
    • Check for faces
    • Check if faces are white listed
    • Check for my dog
  • Process the audio feed
    • Check for any noise
    • Check for non human noises
    • Check for dog barks
    • Check for my and my wife’s voice

These are all stretch goals that will be referred back to as the project moves forward.

Create the Azure IoT Edge module

For the first module, we will use the C Module base image. We are looking for two things from this module:

  • Download the picture feed and pass it to the Edge Hub
  • Download the audio feed and pass it to the Edge Hub

If you don’t know where to get started with the C module of the Azure IoT Edge platform, there is helpful information on the Azure Documentation page. Once the C module is created and ready for editing, we are going to connect to the image feed from the devices. To make this simple, both feeds will be retrieved using HTTP. For the video feed, its simple enough to grab images from the Izon camera existing camera feed.

Now one thing we need, is to be able to connect to each camera within the local network shared with the Edge. Since we would like to be able to add and remove cameras, we will use the device twin to update and manage the list of IP address. The code for updating the list is as follows:

#include <stdio.h>
#include <stdlib.h>
#include "iothub_module_client_ll.h"
#include "iothub_client_options.h"
#include "iothub_message.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/crt_abstractions.h"
#include "azure_c_shared_utility/platform.h"
#include "azure_c_shared_utility/shared_util_options.h"
#include "iothubtransportmqtt.h"
#include "iothub.h"
#include "time.h"
#include "parson.h"
typedef struct IP_ADDRESS_NODE
{
const char * address;
struct IP_ADDRESS_NODE * next;
} ip_address_node;
ip_address_node * add_address(const char * address,ip_address_node * previous)
{
ip_address_node * new_node = (ip_address_node *)malloc(sizeof(ip_address_node));
new_node->address = address;
new_node->next = NULL;
if (previous == NULL)
{
return new_node;
}
previous->next = new_node;
return previous;
}
void delete_address(ip_address_node * current)
{
if (current == NULL)
{
return;
}
delete_address(current->next);
//free(current->address);
free(current);
}
ip_address_node * root_node = NULL;
ip_address_node * add_address_to_root(const char * address)
{
if (root_node = NULL)
{
root_node = add_address(address,root_node);
}
ip_address_node * current = root_node;
while(current->next != NULL)
{
current = current->next;
}
add_address(address,current);
}
static void moduleTwinCallback(DEVICE_TWIN_UPDATE_STATE update_state, const unsigned char* payLoad, size_t size, void* userContextCallback)
{
printf("\r\nTwin callback called with (state=%s, size=%zu):\r\n%s\r\n",
ENUM_TO_STRING(DEVICE_TWIN_UPDATE_STATE, update_state), size, payLoad);
JSON_Value *root_value = json_parse_string(payLoad);
JSON_Object *root_object = json_value_get_object(root_value);
JSON_Array * ipaddresses = json_object_dotget_array(root_object, "desired.CameraAddresses");
if (ipaddresses != NULL) {
delete_address(root_node);
for (int i = 0; i < json_array_get_count(ipaddresses); i++) {
add_address_to_root(json_array_get_string(ipaddresses,i));
}
return;
}
ipaddresses = json_object_get_array(root_object, "CameraAddresses");
if (ipaddresses != NULL) {
delete_address(root_node);
for (int i = 0; i < json_array_get_count(ipaddresses); i++) {
add_address_to_root(json_array_get_string(ipaddresses,i));
}
return;
}
}

view raw
main.c
hosted with ❤ by GitHub

With that code in place, the list of IP addresses can be updated from the Azure UI and the Azure Service SDKs.

Downloading from the Image feed

The Izon cameras make downloading the image feed trivial. There is an existing endpoint where you can grab the latest image directly from the camera’s web server. The latest image is always at /cgi-bin/img-d1.cgi. (NOTE: if you are checking this image from a browser, be sure to have some cache busting!). To download this image into our module, we will use the Curl library for it’s easy HTTP implementation. To add Curl to our Edge module, we will add the following lines to the Dockerfile.amd64.debug:

FROM ubuntu:xenial AS base
RUN apt-get update && \
apt-get install -y –no-install-recommends software-properties-common gdb && \
add-apt-repository -y ppa:aziotsdklinux/ppa-azureiot && \
apt-get update && \
apt-get install -y azure-iot-sdk-c-dev && \
rm -rf /var/lib/apt/lists/*
FROM base AS build-env
RUN apt-get update && \
apt-get install -y –no-install-recommends cmake gcc g++ make libcurl4-openssl-dev && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . ./
RUN cmake -DCMAKE_BUILD_TYPE=Debug .
RUN make
FROM base
WORKDIR /app
COPY –from=build-env /app ./
CMD ["./main"]

FROM ubuntu:xenial AS base
RUN apt-get update && \
apt-get install -y –no-install-recommends software-properties-common gdb && \
add-apt-repository -y ppa:aziotsdklinux/ppa-azureiot && \
apt-get update && \
apt-get install -y azure-iot-sdk-c-dev && \
rm -rf /var/lib/apt/lists/*
FROM base AS build-env
RUN apt-get update && \
apt-get install -y –no-install-recommends cmake gcc g++ make && \
rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY . ./
RUN cmake -DCMAKE_BUILD_TYPE=Debug .
RUN make
FROM base
WORKDIR /app
COPY –from=build-env /app ./
CMD ["./main"]

With curl now added to the image, it can be utilized in code by adding it to the method invoked in our main loop. The code will download the file for each entry in the IP address list. Once the image is downloaded, it will send it as a message to the Edge Hub and add the IP address of the camera to the message header. Here is that code:

struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
char *ptr = realloc(mem->memory, mem->size + realsize + 1);
if(ptr == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
return 0;
}
mem->memory = ptr;
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
struct MemoryStruct download_file(const char * address)
{
struct MemoryStruct chunk;
chunk.memory = malloc(1); /* will be grown as needed by the realloc above */
chunk.size = 0; /* no data at this point */
/* init the curl session */
CURL * curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, address);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
/* get it! */
CURLcode res = curl_easy_perform(curl_handle);
/* check for errors */
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
return chunk;
}
void download_image(IOTHUB_MODULE_CLIENT_LL_HANDLE iotHubModuleClientHandle)
{
ip_address_node * address_node = root_node;
do
{
struct MemoryStruct image = download_file(address_node->address);
if (image.size > 1)
{
IOTHUB_MESSAGE_HANDLE message_handle = IoTHubMessage_CreateFromByteArray((char*)image.memory, image.size);
MAP_HANDLE propMap = IoTHubMessage_Properties(message_handle);
Map_AddOrUpdate(propMap, "IpAddress", address_node->address);
IOTHUB_CLIENT_RESULT clientResult = IoTHubModuleClient_LL_SendEventToOutputAsync(iotHubModuleClientHandle, message_handle, "IncomingImage", NULL,NULL);
if (clientResult != IOTHUB_CLIENT_OK)
{
IoTHubMessage_Destroy(message_handle);
printf("IoTHubModuleClient_LL_SendEventToOutputAsync failed on sending to output IncomingImage, err=%d\n", clientResult);
}
}
free(image.memory);
address_node = address_node->next;
} while(address_node != NULL);
}

view raw
main.c
hosted with ❤ by GitHub

Downloading from the Audio feed

Now that the image feed is being published to the Edge Hub, its time to connect the audio feed. The audio feed is trickier since the Izon camera doesn’t have an easy to use endpoint (that I know of) for downloading the audio samples like we can with the image feed. In the next entry in this series, an Audio feed will be derived from an RSTP stream.

 

5 thoughts on “Hacking Izon Cameras and using Azure IoT Edge

  1. i’m having a credentials problem, none of the user/pass combinations will allow me access to mobileye. Any suggestions much appreciated. Any docs on serial access to this camera’s operating system?

  2. Hey did you ever do the next step and connect to the rstp stream ? I canโ€™t seem to find any info on it any where…trying to get my camera to do stuff again ๐Ÿ™‚ for now the info about static image is good for my purpose but actual video and sound be better.

Leave a Reply to Jared Rhodes Cancel reply