In this post I will explain how the Cam-e-lot sensor sends the level of light in the room to the OpenHAB system.
There two steps involved: calculate the level and light from the image captured by the RaspiCam and send the value to OpenHAB by means of the enOcean transceiver.
Determine level of light in the room
Thanks to the OpenCV library, this task can be accomplished quite easily. The key of the problem is to use the proper color space. The RaspiCam saves images using the widely-used RGB (red-green-blue) format. It's difficult to extract information about light from this color space. However, if you transform the image from the RGB color space to the HSL (hue-saturation-light) color space, everything turns out to be very easy. In the HSL color space, the information about the amount of light can be read from a specific channel: the L channel
So, let's first convert image from RGB to HSL color space
CvSize imgSize = cvGetSize(image);
IplImage* hlsImage = cvCreateImage(imgSize, image->depth, 3);
cvCvtColor(image, hlsImage, CV_RGB2HLS);
Then split the image into its three channels
IplImage* h = cvCreateImage(imgSize, image->depth, 1);
IplImage* l = cvCreateImage(imgSize, image->depth, 1);
IplImage* s = cvCreateImage(imgSize, image->depth, 1);
cvSplit(hlsImage, h, l, s, NULL);
Finally, let's average all the values of the L channel to have a measure of the amount of light in the image
CvScalar avg = cvAvg(l);
Send the measurement to OpenHAB
Now let's face the next challenge.
The enOcean profile I selected (D2-01) includes the possibility to send a measure express on 4 bytes.
This can be accomplished by sending the command 0x07 (Actuator measure response)
The format of the telegram for this command is as follow
| DB_5 | DB_4 | DB_3 | |||||||||||||||||||||
DB_5.Bit 7 <-- 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
Bit ofs 0--> 47 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
|
| CMD | Dim value | I/O Channel | Output value (MSB) |
DB_2 | DB_1 | DB_0 | |||||||||||||||||||||
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
|
| Measured value (LSB) |
where
- CMD
- Dim value
- I/O Channel
- Measured value
To support the new command, I made some changes to the Create method.
eoReturn eoD2EEProfile::Create(eoMessage &m)
{
// New code begins here
if (command == CMD_MEASUREMENT_RESPONSE)
{
tel.RORG = rorg;
tel.SetDataLength(6);
tel.destinationID = destinationID;
tel.sourceID = 0;
// bit 0: power failure (0 -> not supported)
// bit 1: power failure detected (0)
// bit 2..3: not used
// bit 4..7: cmd
tel.data[0] = command;
// bit 8: over current switch off (0 -> not supported)
// bit 9..10: error level (0 -> hardware OK)
// bit 11..15: IO channel
tel.data[1] = 0x00 | (channel & 0x1F);
// bit 16: local control (0 -> not supported)
// but 17..39: output value
tel.data[2] = msg.data[2];
tel.data[3] = msg.data[3];
tel.data[4] = msg.data[4];
tel.data[5] = msg.data[5];
return EO_OK;
}
// New code ends here
return NOT_SUPPORTED;
}
Build the EOLink library as I wrote in my second post and copy the libEOLink.a file (located in EOLink\ReleaseLib folder) to the /usr/lib folder of your Raspberry Pi board
Sending commands
To send commands without breaking up the interface implemented by the eoProfile class, I decided to set the command to perform and the I/O channel of interest by invoking the SetValue method with E_COMMAND for the channelType parameter and 0 or 1 for the index parameter to set respectively the command and the I/O channel. So the code to send an actuator status change is the following
eoProfile *sendProf = eoProfileFactory::CreateProfile(0xD2,0x01,0x00);
eoMessage mytel = eoMessage(6);
// set command to perform (Actuator measurement update)
sendProf->SetValue(E_COMMAND, (uint8_t)0x07, 0);
// set I/O channel (always 0 for measurement)
sendProf->SetValue(E_COMMAND, (uint8_t)0, 1);
// set new value
sendProf->SetValue(E_IO_CHANNEL, (float)value, 0);
sendProf->Create(mytel);
enocean_gateway.Send(mytel);
OpenHAB configuration
To see the measured amount of light, just add a Number item in the items definition file using the ENERGY_WS parameter as in this example
Number LightLevel "Light [%d]" (gCamelot) {aleoncean="LOCALID=01:8E:39:72,REMOTEID=01:85:3A:3A,TYPE=RD_D2-01-00,PARAMETER=ENERGY_WS"}
At this moment in time, the measured value ranges from 0 to 255. I would need a lux meter or another calibration tool to determine a linear mapping between such a value and the actual luminous flux