Я давно хотел заменить обычный термометр за окошком на что-то более современное – на цифровой. Но который будет не просто показывать температуру в более удобном формате, но и записывать её значение в базу данных (например, чтобы потом построить красивый график).
Паять что-то самому не хотелось, поэтому стояла задача обойтись готовыми решениями. Что получилось, читайте под катом.
1. Датчик
В качестве датчика был выбран TEMPer1. Ни по какой-то особенной причине, просто он попался мне первым. Был заказан на eBay у китайских друзей за $10. Первая проверка под виндой показала, что датчик отлично справляется со своей функцией – измеряет температуру. ;)
Поскольку рядом есть как минимум два устройства с линуксом на борту (роутер и спутниковый ресивер), для работы с датчиком захотелось использовать именно их. Покопав немного софт ресивера, я не нашёл там libusb для работы с USB, а вот для роутера эта библиотека была, так что выбор пал на него.
2. DIR-320 и libusb
Итак, я остановился на том, чтобы подключить датчик к имеющемуся DIR-320. После перепрошивки (DD-WRT v24-sp2 mini-usb-ftp, 18946 NEWD), TEMPer появился в /proc/bus/usb/devices:
T: Bus=02 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 14 Spd=1.5 MxCh= 0
D: Ver= 2.00 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
P: Vendor=0c45 ProdID=7401 Rev= 0.01
S: Manufacturer=RDing
S: Product=TEMPer1V1.2
C:* #Ifs= 2 Cfg#= 1 Atr=a0 MxPwr=100mA
Чтобы считать с него показания, понадобится крохотная программа, использующая libusb для работы с USB. Сама libusb входит в стандартные пакеты, так что выполнив
ipkg install libusb
мы получим libusb-0.1.so.4 в /jffs/usr/lib/.
Поскольку нам нужен заголовочный файл usb.h, качаем исходник библиотеки. Сколько я ни пытался, заставить собраться программу с готовой libusb у меня не получилось (интересно, почему?) – линкер упорно матерился, поэтому распаковав исходник, пришлось собрать libusb самостоятельно. Для кросс-компиляции под MIPS был использован toolchain (gcc 4.3.5 uClibc 0.9.30.1) x86 build 2010.12.24. Взять можно здесь. Процесс стандартный: configure и затем make. В результате получилась libusb в два раза больше по размеру, но зато рабочая. Заливаем в роутер, заменяя существующий файл libusb-0.1.so.4.4.2.
3. Софт
На pcsensor.com несложно найти исходник программы, которая считывает показания с датчика. Он и был взят за основу. Была добавлена обработка ошибок и кусок, отправляющий данные на сервер (через простой GET запрос). Вот, что получилось. Компилируем, заливаем на роутер, проверяем – всё отлично работает.
Сама программа запускается примитивным скриптом через cron:
#!/bin/sh
LD_LIBRARY_PATH=/jffs/usr/lib
export LD_LIBRARY_PATH
LIMIT=10
a=1
while [ "$a" -le $LIMIT ]
do
/jffs/temp --report
if [ $? -eq 0 ]; then break; fi
echo "temp failed, run again in 5 sec"
sleep 5
let "a+=1"
done
Цикл пришлось намудрить, поскольку по неизвестным причинам изредка считать показания не удаётся (кто виноват – роутер или сам датчик, не знаю).
На сервере значение температуры заносится в базу с помощью простого перлового скрипта. Как использовать эти данные, зависит, конечно, от задачи. Я просто строю графики колебаний температуры за окном (по часам, по суткам).
4. Калибровка датчика
На сайте производителя заявлена разрешающая способность 0.06°C и точность ±2°C. Для бытовых целей вполне достаточно. Интересно проверить, насколько выдаваемые датчиком значения температуры соответствуют реальным. В домашних условиях навскидку можно предложить три источника известной (с небольшими погрешностями) температуры: морозилка (вода со льдом, 0°C), чайник (кипящая вода, 100°C) и ртутный градусник (34-42°C).
Наиболее близкие значения дала такая поправка (см. исходный код):
int t = a[3] + (a[2] << 8);
t += 208;
float temp = t * (125.0 / 32000.0) * 1.045;
Вполне возможно, что для других экземпляров устройства нужны будут другие значения коэффициентов.
Таким образом, подключив дешёвый USB-термометр к роутеру, получили автономное решение для измерения температуры за окошком, внутри системного блока или ещё где-то. Надеюсь, кому-то это решение пригодится.
Автор: EvgeshaS
Как компилировать приложение и Libusb? Распишите пожалуйста подробнее, желательно под Windows.
Доброй ночи.
Собрал libusb таким образом:
AR=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-ar \
AS=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-as \
LD=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-ld \
NM=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-nm \
CC=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-gcc \
CPP=”/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-gcc -E” \
GCC=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-gcc \
CXX=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-g++ \
RANLIB=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-ranlib \
STRIP=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-strip \
CPPFLAGS=”-O2 -pipe” \
./configure \
–build=i386-pc-linux-gnu \
–host=mipsel-linux \
–target=mipsel-linux \
–disable-udev
Скопировал libusb.h в /dop/current-toolchains/toolchain-mipsel_gcc4.1.2/include/
Скопировал libusb-1.0.so.0.1.0, libusb-1.0.so в /dop/current-toolchains/toolchain-mipsel_gcc4.1.2/lib/
https://github.com/ermolenkom/noolite
Заменил в makefile псс на toolchain-mipsel_gcc
export LD_LIBRARY_PATH=/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/lib/:$LD_LIBRARY_PATH
export PATH=$PATH:/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/
export SDL_INCLUDE=-I/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/include/
export SDL_LIB=-L/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/lib/
Получаю:
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/mipsel-linux-gcc -o noolitepc noolitepc.o -lusb-1.0
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_create’
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_mutexattr_destroy’
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_mutexattr_settype’
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_mutexattr_init’
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_mutex_trylock’
/dop/current-toolchains/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../mipsel-linux-uclibc/lib/libusb-1.0.so: undefined reference to `pthread_join’
collect2: ld returned 1 exit status
make: *** [noolitepc] Ошибка 1
Как победить?