Hola, me dicen Dedoverde

I’m starting growing Bhut Jolokia and other peppers out of seeds. I would like to automate, monitor and document as much as possible the process so that I decided to build an overkill programable power board out of stuff I ordered some time ago from DX as well as some scrap parts. This includes:

For this first milestone, I only want to be able to schedule events like turn heater, lighting or irrigation circuits on & off independantly. Later I would like to take advantage of the remaining inputs of the embeded MCU to read temperature and humidity sensors like this one for example.

Bitlash

The power board 8-bit MCU will run an enhanced version of Bitlash. Enhancements include:

  • atime user function allowing to set/get the date/time from a real time clock;
  • a Unix like cron service relying on the Bitlash task scheduler: the cron service will check every seconds if cronjobs must be run;
  • a few user functions used to interact with the cron service: addcronjob, delcronjob, erasecrontab & lscrontab;
  • a basic watchdog mechanism which will warn me whem something’s wrong (too many consecutive faulty cronjobs): the watchdog will play the Super Mario tune through the piezo buzzer every minutes in such case.

The code is available on github here.

In the following examples, I’m connected to my power board using screen:

screen /dev/ChilliPowerBoard 57600

Switching power plugs

The MCU digital ouputs used to control the power plug relays go from d2 (plug 1) to d5 (plug 4). For example, in order to switch the third plug on, one would type in the power board shell:

> d4=1

In order to toggle the second one:

> d3=!d3

This one could be the building block of an Annoy-a-tron:

> d2=random(2)

Crontab

The crontab relies on Bitlash task scheduler. It runs once per second:

> ps
0: cronsvc

Toggle the plug #1 every 10 seconds:

> addcronjob(-10,-1,-1,-1,-1,-1,-1,"d2=!d2",0)
> lscrontab
JOB|   s    m    h  dow  dom    M    Y | CMD
 0 |*/10    *    *    *    *    *    * | d2=!d2

Delete cronjob 0:

> lscrontab
JOB|   s    m    h  dow  dom    M    Y | CMD
 0 |*/10    *    *    *    *    *    * | d2=!d2
> delcronjob(0)
> lscrontab
JOB|   s    m    h  dow  dom    M    Y | CMD

From monday to friday, Switch on plug #2 from 8am to 11:30am:

> addcronjob(0,0,8,0b01111100,-1,-1,-1,"d3=1",0)
> addcronjob(0,30,11,0b01111100,-1,-1,-1,"d3=0",1)
> lscrontab
JOB|   s    m    h  dow  dom    M    Y | CMD
 0 |   0    0    8   7C    *    *    * | d3=1
 1 |   0   30   11   7C    *    *    * | d3=0

Erase the crontab:

> erasecrontab

EEPROM

All the cronjobs are stored in the MCU’s’ EEPROM so that the number of job is limited. Since Bitlash is also using the EEPROM to store functions, we need to tell it at compile time how much of it can be used (see the “Reserving EEPROM for Other Applications” section in the Bitlash User’s Guide).

Dump of the EEPROM:

> peep

E000:  cron svc$   cro nd;   $sta rtcr  ond$  cro  nd;  run   cron svc,  1000 ; $p  lug$ $...
E040:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E080:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E0C0:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E100:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E140:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E180:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E1C0:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E200:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E240:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E280:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E2C0:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E300:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....
E340:  .... ....  .... ....  .... ....  .... ....  .... ....  .... ....  .... ...�  .... ..d2
E380:  =!d2 $$$$  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����
E3C0:  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����  ���� ����  ���� ���.

Bluetooth setup (Pimp my HC06)

First thing I’m going to do, is setup the BT module.

According to the product datasheet (chapter 9 “AT command set”), one can change the name, the baudrate as well as the pin of the module sending AT commands on its serial interface.

In order to do so, I will use an Arduino nano connected to my computer and loaded with a serial pipe program. Then, I will just send the correct AT commands from a serial terminal. I’m using the “serial monitor” built into the Arduino IDE but one could use gtkterm or even screen.

The pipe program:

 1 #include <SoftwareSerial.h>
 2 
 3 SoftwareSerial btSerialAdapter(2, 3); // RX, TX
 4 
 5 void setup() { 
 6   Serial.begin(9600);
 7   while (!Serial);
 8   btSerialAdapter.begin(9600);
 9 } 
10 
11 void loop() { 
12   if(Serial.available()) {
13     btSerialAdapter.write(Serial.read());
14   }
15   if(btSerialAdapter.available()) {
16     Serial.write(btSerialAdapter.read());
17   }
18 }

and the circuit:

JY-MCU

We’re ready to send the AT commands:

Linux setup

Let’s go through the few steps needed to easily talk to the power board from Linux.

  • First thing is to retrieve the device address:
1 $ hcitool scan
2 Scanning ...
3   00:12:10:23:02:31 ChilliPowerBoard
  • Then we can add some stuff in/etc/bluetooth/rfcomm.conf to connect auto-magically at startup:
 1 #
 2 # RFCOMM configuration file.
 3 #
 4 
 5 rfcomm0 {
 6         # Automatically bind the device at startup
 7         bind yes;
 8 
 9         # Bluetooth address of the device
10         device 00:12:10:23:02:31;
11 
12         # RFCOMM channel for the connection
13         channel 1;
14 
15         # Description of the connection
16         comment "Chilli Power Board";
17 }
  • Then we setup permission on the /dev/rfcomm0 file and tell modem-manager not to probe the power board. In /etc/udev/rules.d/100-ChilliPowerBoard.rules (create this one):
KERNEL=="rfcomm0", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"
  • Add ourselves to the dialup group (or whatever group is used for rfcomm on your distrib). In /etc/group:
dialout:x:20:sb
  • Optionally create a user friendly symlink:
$ sudo ln -s /dev/rfcomm0 /dev/ChilliPowerBoard
  • Manualy connect to the power board ?
1 $ sudo rfcomm connect 0
2 Connected /dev/rfcomm0 to 00:12:10:23:02:31 on channel 1
3 Press CTRL-C for hangup
  • Disconnect …
$ sudo rfcomm release 0
  • Talk to the board:
$ screen /dev/ChilliPowerBoard 57600
  • Optionally create a user friendly alias:
$ alias ChilliPowerBoard="screen /dev/ChilliPowerBoard 57600"

That’s all ! The BT module is now ready and I will keep it on a corner of my desk until it’s time to put everything together. The next stage is to hack a little RTC circuit.

Real Time Clock

Since I’m willing to schedule events at a given date and time on my power board, it needs to track time pretty accurately. ### Basic circuit I had a spare PCF8583 I2C real time clock I decided to use:

PCF8583P

All it needs is a 32.768Khz crystal (\(2^{15}\) cycles per seconds). The basic circuit looks like this:

RTC circuit on breadboard

According to another datasheet, page 10 of 52, the theoretical capacitance required at OSCI is 18pF. The corresponding capacitor should be connected to \(V_{DD}\) (page 11 of 52). I added one to the circuit in the end. I choosed not to use a trimpot capacitor \(C_{trim}\) (5 to 25pF as per datasheet) since I can easily compensate for the expected 5 minutes error a year by resetting the RTC via bluetooth, based on NTP time for example (see page 24).

Also, page 12 of 37, it is said that > If the alarm enable bit of the control and status register is reset (logic 0), a 1 Hz signal is observed on the interrupt pin \(\overline{INT}\).

and page 13: > In the clock mode, if the alarm enable is not activated (alarm enable bit of the control and > status register is logic 0), the interrupt output toggles at 1 Hz with a 50 % duty cycle (may > be used for calibration).

Here is what I observe (looks good to me):

RTC 1Hz signal

Power backup

RTC circuits often come with a backup power. For example a 3V coin battery. A simple way to implement this is a diode based “OR-ing” circuit.

Here is a little schematic and an attempt at explaining how it works (I hope you can read my handwriting): OR-ing

The circuit upgraded with a backup power: RTC circuit with backup power on breadboard

I only had 1N4150 diodes available. Best practice for this circuit is to use Schottky diode in order to minimise the forward voltage drop.

I measured the current with and without primary power supplied and checked against the datasheet (page 21). The measured current is higher than what’s expected (4.3 vs ~3 micro amps @ 3V). I wonder why.

Since the circuit is simple, I decided to transfer it on a stripboard:

This wasn’t a great idea. The clock is either running too fast or too slow. Just like this guy. Hopefuly the UM10301 datasheet, section “14. PCB layout guidelines” will allow me to create a proper PCB. But that will be another time.

Also it’s worth noting that a DX RTC module costs about 3 yankee dollars.

That’s all for the RTC hardware. Let’s talk quickly about the software.

Software

On the software side, a PCF8583 Arduino library is available on github:

  • it’s incomplete because I found out that a dude called jiki974 added support for the daily alarm but these changes never made it to the repo;
  • it’s somehow buggy since it ignores the day of the week and doesn’t really cope well with leap years.

Anyway, I submitted a pull request to cope with these issues.

Interacting with the component is done via read and write operations from and to its CMOS RAM. The map of the RAM is at available page 8 of the datasheet.

Ultimately this is what a time command using the PCF8583 library looks like in Bitlash:

 1 numvar time() {
 2     if(getarg(0) == 0) {
 3       static const char* DayStrings[] = {
 4         "Sunday", "Monday", "Tuesday", 
 5         "Wednesday", "Thursday", "Friday", 
 6         "Saturday"};
 7       theRTClock.get_time();
 8       char t[50];
 9       sprintf_P(t, PSTR(" %04d/%02d/%02d %02d:%02d:%02d"),
10         theRTClock.year, theRTClock.month, theRTClock.day,
11         theRTClock.hour, theRTClock.minute, theRTClock.second);
12       sp(DayStrings[theRTClock.get_day_of_week()]); sp(t); speol();
13     } else if(getarg(0) == 6) {
14        theRTClock.year= getarg(1);
15        theRTClock.month = getarg(2);
16        theRTClock.day = getarg(3);
17        theRTClock.hour = getarg(4);
18        theRTClock.minute = getarg(5);
19        theRTClock.second = getarg(6);    
20        theRTClock.set_time();
21     }
22    return 0;
23 }

Flashing the MCU

I’m programming the MCU using a USBtinyISP clone, bypassing the bootloader. I find this method really reliable and it allows me to play with the fuse bits as well.

It looks like this:

Programming the Mini using ISP

On my Linux distribution, I setup credentials for the USBtinyISP by creating a /etc/udev/rules.d/103-USBtinyISP.rules file containing:

SUBSYSTEM=="usb", ATTR{idVendor}=="1781", ATTR{idProduct}=="0c9f", GROUP="plugdev", MODE="0666"

I must tell the Arduino IDE I’m using an ISP programmer: File => Upload Using Programmer or Ctrl+Shift+U, as well as select the proper programmer in Tools => Programmer. I could also use avrdude directly:

$ avrdude -v -c usbtiny -p m328p -U flash:w:ChilliPowerBoard.hex

Putting everything together

  • Software: check !
  • BT <=> serial pimping: check !
  • DIY RTC: check ! (kinda)
  • Flashed MCU: check !

We’re good to go. Here is the plan:

Fritzing breadboard

Its implementation looks like this:

Everything together

Now comes the real challenge: fit everything in the power board …

Conclusion

It’s a bit scarry and looks like a dangerous protoype. It works just fine. In the near futur I plan to design a proper RTC circuit, hack an Android app to control the board and ultimately read temperature and humidity sensors. That’s all folks.



blog comments powered by Disqus

Published

05 December 2013

Category

Home automation

Tags