I recently purchased the excellent Seneye aquarium monitor. It is a small device with that sits in a fish tank and monitors various parameters.
I’d been looking for a simple device like this for some time – not too complex, not too expensive. It may not sense some parameters needed in a marine tank however it does do the basics such as temperature, in/out of water, ammonia and pH. As I mentioned before, water chemistry is difficult and you shouldn’t knock those who have tried. Other devices are more complex, expensive, or actually never successfully made it to market. In essence it reads the colour change of a litmus strip by comparing it to a sealed reference, as well as temperature and water refraction.
The challenge came about because although they have a cloud solution that transmits readings every 30 minutes, the device itself has to connect to a Windows PC and thence to the cloud. I’d looked at running a low-powered Windows SBC or even purchasing Seneye’s always-on connection device, but the easiest seemed to be to read the USB device.
USB devices
USB devices are a wonder to behold. They do a lot of work internally and the USB protocol spec runs for many pages. I looked for libraries to help me read the device and found a couple which work in Python, my language of choice. USB also delineates a special form of device known as the ‘HID’, or Human Interface Device. These are things such as USB mice, track-pads and keyboards. They have a simpler interface and only use a couple of the modes of transfer: control, and interrupt.
Walking the USB tree
As USB devices have a hierarchical protocol we need to find out some things about it.
- Device
- Configuration
- Interface
- Alternate setting
- Endpoint
We start by looking at the device itself using Linux commands and the udevadm command. The udevadm command may not be installed on your system and should be installed using your distro’s package manager.
Firstly, using lsusb we get to see where our device is sitting on the bus – and note that this changes every time we plug it in.
lsusb Bus 002 Device 089: ID 24f7:2204
… so our device is on the bus number 2, and is at device number 89. Now, using udevadm we can test this and get the device characteristics:
udevadm info -a -p $(udevadm info -q path -n /dev/bus/usb/002/089) looking at device '/devices/pci0000:00/0000:00:14.0/usb2/2-1': KERNEL=="2-1" SUBSYSTEM=="usb" DRIVER=="usb" ATTR{authorized}=="1" ATTR{avoid_reset_quirk}=="0" ATTR{bConfigurationValue}=="1" ATTR{bDeviceClass}=="00" ATTR{bDeviceProtocol}=="02" ATTR{bDeviceSubClass}=="00" ATTR{bMaxPacketSize0}=="64" ATTR{bMaxPower}=="250mA" ATTR{bNumConfigurations}=="1" ATTR{bNumInterfaces}==" 1" ATTR{bcdDevice}=="0125" ATTR{bmAttributes}=="80" ATTR{busnum}=="2" ATTR{configuration}=="" ATTR{devnum}=="89" ATTR{devpath}=="1" ATTR{idProduct}=="2204" ATTR{idVendor}=="24f7" ATTR{ltm_capable}=="no" ATTR{manufacturer}=="Seneye ltd" ATTR{maxchild}=="0" ATTR{product}=="Seneye SUD v 2.0.16" ATTR{quirks}=="0x0" ATTR{removable}=="removable" ATTR{serial}=="F500214755881923AEAEA4260100D020" ATTR{speed}=="12" ATTR{urbnum}=="32" ATTR{version}==" 2.00"
From this we can see that the device has one configuration and one interface. It also contains the device’s serial number. Other notable things are the maximum packet size, and the power requirements. That number of interfaces response is a little odd?
Can the raspberry pi 3 and a display work with Seneye ?
Any single-board computer (RasPi 3, odroid, beaglebone, …) with a USB connection can read the Seneye and display the results. Just take my code and change it to write to a screen. But the challenge is that the Seneye accumulates readings and does not clear them until secret protocols are used. I did not attempt to discover these secret protocols, and only use the public ones released by the Seneye company.
An attempt to wireshark the usb traffic between the Seneye Home and the Windows App reveals the communication looks nothing like the documented API. The data packets are still 64 byte packets but the payloads both to and from the device are very different. A wireshark capture on a linux box when running your Python code looks as one would expect.
An attempt to wireshark the usb traffic between the Seneye Home and the Windows App reveals the communication looks nothing like the documented API. The data packets are still 64 byte packets but the payloads both to and from the device are very different. A wireshark capture on a linux box when running your Python code looks as one would expect.