Adding 433MHz RC to ESP8266-01

esp266-433Currently I have a homeautomation system on an Arduino. It uses 433 Mhz to switch lamps and stuff. It works fully automatic and if i want to intervene I use bluetooth to give commands.
It works well, but if I am away from home, I cannot intervene or check anything anymore. So I started to transfer the entire Arduino based system to an ESP8266.
Obviously that is a big overhaul and one of the first things I wanted to check is how well my 433 Mhz switches could be integrated with an ESP8266.
As such code might be beneficial to others, I thought I’d publish it here.
The 433 Mhz library I use is the enhanced RemoteSwitch library. I find that a bit more pleasant than the RCSwitch library because for many (not for all) remote switch sockets you do not need to sniff any code. Just knowing what type of Switch you have is enough.
The example below switches 4 sockets. I have explained the use of those switches with the RemoteSwitch library in another post. Obviously I switch many more in my house, but I wanted to keep things in this example simple. I am using an ESP8266-01, the simplest of the ESP8266 modules. I use GPIO2 to connect to the signal pin of a 433 MHz transmitter and feed everything with 3.3 Volt. As the ESP8266 is working on 3.3Volt, the transmitter is also working on 3.3Volt. I didnt notice any problem with that, but it is better to use a decent antenna that is easy to make, rather than just a 1/4 wavelength rod. Under no circumstance put 5 volt on any of your ESP8266 pins. If for whatever reason you need or want to feed the transmitter with a higher voltage, then I presume it is ok to still connect the GPIO2 pin to the data pin of the transmitter, as I presume that doesnt carry a voltage (but better do not risk it), but the transmitter may not recognize the ESP8266 output as HIGH. Adding a levelconverter may be necessary then, but to be clear: It works well with 3.3 Volt for the transmitter
The Sketch is quite straightforward. I included 4 switches as example. Therefore there are 8 buttons defined (ON and OFF for each channel.
If you want to add more switches, add the names for these in the Array. The program will automatically generate the required buttons. Add the On and Off codes for yr switch to code for the pages via a Switch /case statement.
When you start the program the relevant connection data is printed in the serialmonitor but the IP that you need can also be checked in the DHCPclient list of your router

/*
    This Sketch demonstrates the use of the Extended RemoteSwitch Library  with an ESP8266-01 WiFi module
    The setup is as follows:
    Supply module with 3.3 Volt
    Attach  pin GPIO2 with the signal pin of a 433 Mhz transmitter module
    The names you want to attach to the Buttons are defined in  the array "socketnames"
    the number of sockets can be extended. Pages are dynamically generated based on the
    size of the array as calculated by "ARRAY_SIZE"
    The use of  4 different modules is demonstrated:
    ELRO AB440
    Blokker /SelectRemote 1728029
    EverFlourish EMW203
    Eurodomest 972080
    Basic idea from Alexbloggt
    23-09-2016 DIY_bloke
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <RemoteSwitch.h> //FuzzyLogic extended lib

/************************************************
            Object Declarations
 ***********************************************/
ElroAb440Switch ab440Switch(2);
BlokkerSwitch3 blokkerTransmitter(2);// SelectRemote 1728029
EverFlourishSwitch everswitch(2);  // EverFlourish EMW203
Ener002Switch enerswitch(2);      // Eurodomest 972080
//  Fill out the base address of YOUR Eurodomest switch
const unsigned long euro  = 823149;  // base adres eurodomest  : 11001000111101101101  Supply the baseaddress of YOUR Eurodomest
#define ElroAAN ab440Switch.sendSignal(29, 'A', true)
#define ElroUIT ab440Switch.sendSignal(29, 'A', false)
#define BlokkerAAN blokkerTransmitter.sendSignal(1, true)
#define BlokkerUIT blokkerTransmitter.sendSignal(1, false)
#define EverFlourishAAN everswitch.sendSignal('A', 1, true)
#define EverFlourishUIT everswitch.sendSignal('A', 1, false)
#define EnerAAN enerswitch.sendSignal(euro, 1, true)
#define EnerUIT enerswitch.sendSignal(euro, 1, false)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
MDNSResponder mdns;
// Replace with your network credentials
const char* ssid = "YourSSID";
const char* password = "YourPassword";
ESP8266WebServer server(80);
// Define names of your buttons here, number of buttons will be  automatically adapted
char* socketnames[] = {"ELROAB440", "Blokker", "EverFlourish", "ActionSwitch"};
int numofsockets = ARRAY_SIZE (socketnames);//bevat de grootte van het Array
// sample css and html code
String css = "body {background-color:#ffffff; color: #000000; font-family: 'Century Gothic', CenturyGothic, AppleGothic, sans-serif;}h1 {font-size: 2em;}";
String head1 = "<!DOCTYPE html> <html> <head> <title>RemoteSwitch Demo</title> <style>";
String head2 = "</style></head><body><center>";
String header = head1 + css + head2;
String body = "";
String website(String h, String b) {
  String complete = h + b;
  return complete;
}
void setup(void) {
  // adapt body part of html if necessary
  body = "<h1>RemoteSwitch Demo</h1>";
  // socket names and buttons are created dynamical
  for (int i = 0; i < numofsockets; i++) {
    String namesocket = socketnames[i];
    body = body + "<p>" + namesocket + " <a href=\"socket" + String(i) + "On\"><button>ON</button></a> <a href=\"socket" + String(i) + "Off\"><button>OFF</button></a></p>";
  }
  body += "</center></body>";
  delay(1000);
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // serial output of connection details
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  if (mdns.begin("esp8266", WiFi.localIP())) {
    Serial.println("MDNS responder started");
  }
  // this page is loaded when accessing the root of esp8266´s IP
  server.on("/", []() {
    String webPage = website(header, body);
    server.send(200, "text/html", webPage);
  });

  /************************************************
                        Dynamically creating pages
   *********************************************** */
  for (int i = 0; i < numofsockets; i++) {
    String pathOn = "/socket" + String(i) + "On";
    const char* pathOnChar = pathOn.c_str();
    String pathOff = "/socket" + String(i) + "Off";
    const char* pathOffChar = pathOff.c_str();
    //content ON page
    server.on(pathOnChar, [i]() {
      String webPage = website(header, body);
      server.send(200, "text/html", webPage);

      switch (i)
      {
        case 0:
          ElroAAN;
          break;
        case 1:
          BlokkerAAN;
          break;
        case 2:
          EverFlourishAAN;
          break;
        case 3:
          EnerAAN;
          break;
        default:
          break;

      }
      delay(500);
    });
    //content OFF page
    server.on(pathOffChar, [i]() {
      String webPage = website(header, body);
      server.send(200, "text/html", webPage);

      switch (i)
      {
        case 0:
          ElroUIT;
          break;
        case 1:
          BlokkerUIT;
          break;
        case 2:
          EverFlourishUIT;
          break;
        case 3:
          EnerUIT;
          break;
        default:
          break;

      }
      delay(500);
    });
  }
  server.begin();
  Serial.println("HTTP server started");
}
void loop(void) {
  server.handleClient();
}

Reset a program from a ‘freeze’

While doing a test run on software for an incubator the software did fine, until suddenly on the ninth day weird things started to happen: the LCD showed some odd data and in spite of a low temperature the heating had not kicked in. I resetted the software, wondering what it could be but only an hour later again something off happened. This time in spite of the temperature being well over the upper limit, the heating was not switched off.
I checked my code, which really wasn’t so complicated: Read DSB1820, read DHT11, compare with high and low limit, switch a pin on or off and write the value to an LCD and I couldn’t find a single mistake and don’t forget, it had run flawlessly for 9 days. I suspected my display. This was a 20×4 LCD with I2C module with 4k7 pull up. Nevertheless there might still have been some ‘static’ on the SDA and SCL lines that supposedly can cause the Arduino to freeze.

Obviously that is not good if you are running an incubator as you dont want to check it and find your eggs boiled.
So, other than maybe straightening out the LCD cables a bit, I decided that I needed some software protection against ‘freezes’
The only (and possibly best) way to do this is with the watchdog timer. I dont want to go into the specifics and the background of the watchdog timer, but just keep it on a practical level.
What we do is to set-up the watchdog timer to initiate a system reset after say 4 seconds. Then in our loop we do a reset of the watchdog timer so it starts counting from zero again. So as long as the program tells the watchdog timer “I am still running” nothing will happen. Should the program freeze up, it will not reset the watchdog timer and then after 4 seconds the watchdog timer will reset the entire system.
It is very well possible to use the watchdog timer by manipulating the various registers yourself, but it is much simpler to use the watchdog libary that is part of the avr libraries.
We do this as follows:

#include <avr/wdt.h>

void setup()
{
	wdt_disable();
	//wdt_enable(WDTO_1S);// 1 sec
	wdt_enable(WDTO_2S);// 2 sec
	//wdt_enable(WDTO_4S);// 4 sec
	//wdt_enable(WDTO_8S);// 8 sec
}

void loop()
{
	wdt_reset();
	//  your program
	........
}

Solar powering an Attiny or Arduino with a capacitor, or just use AA? Part 2

Solar Charging a capacitor
Solar Charging a capacitor

As I had a 10.000uF (0.01F) capacitor and was awaiting my supercapacitors, I was wondering if I could perhaps use that, just to carry a circuit through the night.

With the aid of a 9 Volt Solarpanel (and a resistor) the 10.000uF capacitor was charged to 10Volts fairly quickly (it was a sunny day).

The charge in that can be calculated by 1/2*0.01*10² =0.5Ws. But as we can only use it at 5 Volt level in reality that is 0.125 Ws.
Also, as we take 1.8 Volt as our lower limit, we have to subtract 0.0126 Ws, leaving us with 0.109Ws.

With the earlier stated power consumption of 13.8uWatt that leaves us with about 7900 seconds or 2 hours and 12 minutes, which is obviously not enough to carry us through the night.
Yet, I wanted to test whether I was on the right track, so I used the following circuit to connect my circuit to the fully charged capacitor:
5volt

As it turned out, my circuit lasted for 1 hour and 25 minutes before it appeared to be dead, which i guess is close enough to the calculation, considering it was an old (>20 yrs) capacitor that might have suffered and maybe  had a bit of a leak current. Now before I get criticized that I am not taking into account that the capacitor is also discharged  during the day because it has to feed the circuit then as well… yes that is true, but I merely wanted to see if the capacitor could store enough load to begin with, to carry me through the night, which it cant. The charge -and thus the capacitor- would need to be at least  some 9 times bigger (so a 100.000uF minimally). I could have figured that all out just by calculation, but nothing beats a field test to see if calculations are right.

Anyway, while waiting for my supercapacitors to arrive (aliexpress) I had some time to think about what solarcell to use. The 9 Volt (5 Watt I seem to remember) seemed definite overkill, but from a few old gardenlamp I had some small solarpanels that delivered 2.5 Volt. I could put 3 of those in series (as they only give 2.5 Volt on a sunny day). I had no idea what Wattage they are but they are used to charge a 1.2V 40mAh NiCad, and some 300mAh NiCad. The latter seemed a better choice.
Ofcourse I could buy a solarpanel, but I first wanted to try with what I had available.

In part 1 I calculated a 1.5 Farad capacitor at 5 Volt is charged up to 19.5 Joule or 19.5 Wattseconds.
So if one wants to charge that capacitor with say a 5 Volt 1 Watt solarpanel one would need  a minimum of 19.5 secs to charge it (if we forget about a series resistor for a while).

IMG_20160505_172103Thriftstores sell these small solar Garden lights  usually for less than a euro. They have a small solarcell and inside a circuit build around an YX8018 IC that charges a single NiCad cell. Sometime sometimes a very small one (40mah)  sometimes a bigger one (800mAh). They need a full day of sun to charge and at dark an LED  lights up for a few hours. Now suppose the small solarpanels from my garden light are indeed enough to charge a 1.2 V 40mAh cell if left to charge for say 8 hrs.
The cells are  1.2 *40 mWh =48 mWh. If charged over 8 hrs that leaves a solar cell of 6mW. As the cells give 2.5 Volt in bright sun light, I would need 2 which then gives a total of 12mW (this is just theoretical, it is very low for a solarcell). So if I need a charge of 19.5W.s, that comes down to (19500/12=) 1625 secs or 27 minutes or 0.5 hrs to charge the 1.5 Farad capacitor. That is doable (if we  forget about the poweruse in the daytime).
In that 0.5 hrs obviously 13.8uW*0.5=6.2uWh is used just for the working of that circuit, which is small enough to ignore in terms of charge time. So, if a 1.5 Farad takes 0.5 hrs to charge, my 10.000uF should take 20/100 m or  12 secs. Lets see.
Now before I go on, just a word of warning: the calculations I do are partly limit calculations and do not always take all practical realities into account. For instance, a 5 Volt 12mW cell will be able to deliver 12/5=2.5mA. However if one tries to load an empty capacitor  with a series resistor of say 100 Ohm, then the max current that is requested is 50mA, obviously the photo cell cannot deliver that so the voltage drops and therefore the classical natural log curve of  charging a capacitor will not be followed. For any given moment the curve will follow the natural log curve for the  voltage at that moment, leading to a longer charge time.
Just a word: One could use the innards of the cheap garden light so, including the circuit around XY8018 IC to charge the caps, if one brings it up to 5 Volt. Various  circuits for that exist. I however decided to keep it simple and do a straight laod from  one or more  fotovoltaic cells.
Nevertheless, as halfway through my experimentations my Ultracaps arrived from Aliexpress (very fast delivery), it didnt seem much use to experiment with the 10.000uF any longer, so in Part 3 We go to the real work.
By the way, someone has already done some work on this.

 

Solar powering an Attiny or Arduino with a capacitor, or just use AA? Part 1

If you have a processor in a remote location that you cannot or will not bring a psu cable to, you have several options of supplying it with energy.
Batteries come to mind and these could be rechargeable or not, or one can use a capacitor. After all, those store energy as well. To make a capacitor a viable option, obviously it needs to be a big one (in capacity, not especially in size), and one has the option of adding a solar cell to it.
As I wanted to feed an attiny that is somewhere in my garden and that is asleep most of the time and as I had some idle solar panels  (9 Volts, 2 Volts) those seemed  suitable to use, but as they do not provide much energy during the night, I needed to store that energy as well. As storage Nicads or even a LiPo came to mind. A Lipo I discarded as it takes some extra circuitry to do any decent charging. A nicad obviously needs some consideration in charging and discharging  as well, but they are more tolerant albeit that a deep discharge is usually not appreciated by them, nor is a constant charge.
Therefore I also considered using a “supercapacitor” I have a capacitor of 10.000uF but one can hardly call that a supercapacitor, but nowadays supercapacitors are readily available at modest prices. They would be easy to use in a charging circuit (basically a resistor would be enough) and they don’t mind frequent  charge and discharge. As their charge is  limited, obviously I would need a solar-cell, so the only thing I needed to see is if they would carry my application ‘through the night’

The Charge of a capacitor is expressed in Coulomb (symbol C).
this can be expressed as:

C=F * V  (where of course ‘F’ stands for the capacity in Farad)
Energy in Joule is expressed as:
J=C*V
Which is:
F*V*V  of F.V²
However, at a given voltage and capacity only half of the energy is available to charge the capacitor hence the energy in the capacitor will be:
J=½ * F *V²
and Joules can also be expressed as ‘Wattseconds’:
J=W *s

So if we calculate the number of Joules in the capacitor at 5.1 Volt:
J=0.5 * 1.5 * 5.1² = 19.5 J
Now obviously we will not all use those as the attiny kinda stops working at 1.8 Volt. If we calculate the number of Joules still left then we come to
J=0.5 * 1.5 * 1.8² = 2.43 J
So the amount of usable energy comes to 19.5-2.43= 17J (rounded down)

From an earlier project on  an attiny13 that was put to sleep only to awake every so many seconds, I found out that the current consumption was 5.5 uA at 5 Volt. Now obviously it will consume a bit less when the voltage drops, so lets assume 4uA at an average of 3.45 Volt (The average voltage being (5.1+1.8)/2=3.45 Volt).
We can calculate the average power consumption as V*I:
3.45 * 4*10⁻⁶ = 13.8 uWatt
as we have 17 Joules available and 17 joules being 17 Ws (Wattseconds) we can calculate the time:
J=W*s
s=J/W
s=17/(13.8 *10⁻⁶)
s=17/13.8  *10⁶
s=1.23 *10⁶
s=1230 000 sec (1,23 million seconds)
that is:
20.531 min, is
342 hrs is
14 days
Now this is just an approximation as there might be some current leakage. The processor will need to do something when awake, like flash a  led or send something, so it will probably not make the full 14 days, but that is not important as it is obviously enough to carry us through the night and probably an overcast day as well.

So how would this be if I used normal AA batteries or NiCad batteries?
As example for regular alkaline batteries  I will take the ubiquitous Philips  LR6. Fortunately someone else already calculated the energie stored in these batteries  at  1986 mAh at a discharge of 100mA. As the performance of these batteries is increasing when the discharge decreases, I will use 2000mAh for my calculations.
If one uses 3 of those to get to 4.5 Volts that will be a total of 9000mWh or 9 Wh.
Again, we will not be able to use this all as we have 1.8 Volt as lower limit, so we will be stuck with 3.6 Wh that we cant use, leaving  5.4 Watthour usable energy.
The average Voltage on the  processor will be:
(4.5+1.8)/2=3.15 Volts.
the average power consumption thus is:
3.15* 4*10⁻⁶ = 12.6uW
as we have 5.4 Wh available we can again calculate the time:
h=5.4/12.6 * 10⁶
h=0.428571 *10⁶
h=428571 hr
=17857 days
=592 months
=50 years
Wow. Why would anybody want to use anything else but LR6 batteries ?
Well for several reasons: 3 of those batteries take more space and eventhough they tend to perform well at low temperatures and low discharge rate, we all have experienced that Alkaline batteries left in a hardly used device tend to leak, even destroying that device by its corrosive leaking. Advantages and disadvantages of alkaline batteries are discussed here.
Nevertheless using alkaline batteries can be a good choice, but don’t forget to change them.

Using NiCad batteries gives a somewhat similar calculation. Suppose we use 3 cells of 1.2 Volt 2000mAh (or 2Ah).
Total energy will be 3.6*2= 7.2 Wh
useable energy will be (3.6-1.8)* 2=3.6 Wh
the average voltage we set at (3.6+1.8)/2=2.70 Volt
The average power consumption will be:
2.7* 4*10⁻⁶ = 10.8uW  (V*I)
The time will thus be:
h=(3.6/10.8) * 10⁶
=333333 hr
=38 yrs
Now if that only was true. My experience with  for instance solar garden lights (that often only have an 800mAh cell)  is that they usually dont last through the winter… and mind you, those are being recharged (which could contribute to their demise).
Nevertheless they may be a good choice.

In a following article I will discuss some practical examples

 

1 Wire LCD interface: Part 1

The one wire LCD interface has been around on the internet for some time already and made popular by Roman Black, although he claims he is not the inventor of the principle. His article is mainly PIC processor oriented, but it gives a good explanation of the principle. Myke Predko is also a name that  should not be unmentioned as pioneer in 1 wire LCD driving. Also this article about  one wire driving of a shift register is very informative

The ShiftRegLCD123 website from Raron used to give a lot of information as well, along with circuits, but that (the Wiki) seems to have disappeared. But his library is in codebender.

In brief, the One Wire interface uses a latched shift register in which the clock and the latch are taken from the data signal through two RC networks that produce the necessary delay. Circuits are a plenty on the interweb, but finding the proper driver for it can be confusing sometimes.

Although the interface on the data, clock and latch lines is rather standard, the connection between the shift register and the LCD has thre major variants that for now i will just call the Roman Black, the LCD3Wire circuit (yes, it is 1 wire) and the ShiftRegLCD123 circuit. Also Elektor has published a 1 wire interface (Detlef Hanemann)(Published in issue 9/2015 on page 92) with yet again a different shift register to LCD connection. Their setup is said to have several advantages over the setup used by Roman Black, it uses the Q7′ direct output of the shift register to trigger the output latch register to carry over automatically the shifted data to the output pins. But for that it requires a monoflop built around a BS170 FET to generate the E-pulse. The setup to be used in Francisco Malpartida’s LCD library is yet again different from the other 3 and uses a diode to create an AND gate

1wireLCD
Roman Black

1wireLCD-shiftreglcd

ShiftRegLCD123

1pinlcd-elektuur
Elektuur

onewiremalpertida

 

Malpartida LCD library

. Roman Black LCD3Wire Shiftreglcd Elektuur Malpartida
RS  Qc  Qb  Qc  Qg  Qg
R/W  GND  Qc  GND  GND  GND
E  Qd  Qd  Qh  Qh’  Qh’ sort of
D4  Qe  Qh  Qd  Qa  Qe
D5  Qf  Qg  Qe  Qb  Qd
D6  Qg  Qf  Qf  Qc  Qc
D7  Qh  Qe  Qg  Qd  Qb

Driving these OneWireLCD’s thus differs per configuration. The ShiftRegLCD123 library can do both the ShiftRegLCD and the LCD3Wire protocol. The Liquid Crystal Library of Francisco Malpartida  does have a One Wire protocol but make sure you have the latest version. However, it relies on connections different from the others mentioned:
// Bit #0 (QA) – not used
// Bit #1 (QB) – connects to LCD data input D7
// Bit #2 (QC) – connects to LCD data input D6
// Bit #3 (QD) – connects to LCD data input D5
// Bit #4 (QE) – connects to LCD data input D4
// Bit #5 (QF) – optional backlight control
// Bit #6 (QG) – connects to RS (Register Select) on the LCD
// Bit #7 (QH) – used for /CLR on the HW_CLEAR version (cannot be changed)
// (Q’H) – used for Latch/EN (via the diode AND “gate”) (cannot be changed)

// -----------------------------------------------
//
//                         74HC595     (VCC)
//                       +----u----+     |          2.2nF
// (LCD D7)------------1-|QB    VCC|-16--+      +----||----(GND)
// (LCD D6)------------2-|QC     QA|-15         |
// (LCD D5)------------3-|QD    SER|-14---------+--[ Resistor ]--+
// (LCD D4)------------4-|QE    /OE|-13--(GND)         1.5k      |
// (BL Circuit)--------5-|QF    RCK|-12---------+                |
//                       |         |             \               |
// (LCD RS)------------6-|QG    SCK|-11-----------)--------------+--(Seri
//                     7-|QH   /CLR|-10--(VCC)   /               |
//                  +--8-|GND   Q'H|--9---|<|---+--[ Resistor ]--+
//                  |    +---------+     diode  |      1.5k
//                  |                           |
//                  |      0.1uF                |
//                (GND)-----||----(VCC)         +----||----(GND)
//                                              |   2.2nF
// (LCD EN)-------------------------------------+
// (LCD RW)--(GND)
//

The Elektuur/Elektor configuration has its own program, or here (both direct download link)

A capacitive soil humidity sensor: Part 3

Initially I imagined the probe as a sleek device with a wire coming out that one would stick in the soil, if necessary completely. This would mean that the circuit pcb would be an integral part of the PCB that  formed the plates, but as always, things go different in practice. For one thing , the piece of PCB I intended to use just wasnt long enough. Second, my PCB etching possibilites are temporarily impeded. Third, I wanted to add an LDR, meaning that I had to have some sort of  translucent cover.

I constructed the circuit on a small piece of stripboard:

IMG_20160225_163125 i2cprobe

With regard to the LDR, sure that is nonsense. If I want to add an LDR I  could just as well add it to my base station. But I am not adding it because I have to, I am adding it because I can and because I wanted to get some experience in programming an I2C slave. An LDR might not be so usefull but in future I may want another sensor, e.g.a sensor that reads if there is really water flowing from the irrigation tube.

Also I had decided on putting the capacitor plates back to back, but as I did not have double sided PCB I just used two pieces glued and  soldered(!) together.
So My BOM was rather simple:

  • 2 equal size pieces of PCB  Size depends on what you have, but do not make them too small. I used 12×3 cm.
  • 1 piece of 0.5-1.0 cm plastic for a baseboard. I used an old cutting board.
  • 1 clear/translucent cover, I used the lid of a whipped cream spray can.
  • 1 piece of  thin 4 wire cable, length depending on your need

pcbprobe2I glued the two piecesof pcb back to back. drilled a hole in all 4 corners and through soldered a piece of wire through each hole, thus anchoring the plates together. I removed some copper around the solder so it would become an island isolated from the rest of the plate. (See picture).

Soldering the plates together in the corners may not be necessary if you decide to electrically isolate them from the soil with e.g. shrink tube.

Eventually I will place an NTC on the plate as well after it is covered with Shrink tube. Esthetically it might be better to put the NTC under the shrink tube, but that could create an air pocket.

 

baseplateI made the base plate from a o.5 cm thick piece of soft plastic. Cut out a round shape  with a 5.5 cm diameter to fit the base of my  clear dome and  made a slit 3 x0.3 cm into that in which the PCB  fits snug. made a round hole for the connecting cable.

IMG_20160226_133820

 

 

I soldered two wires on the top of the PCB, one on each side. Soldered wires on an NTC, insulated those, attached the NTC to the bottom of the PCB with the wires leading to the top and then covered the PCB with shrink wrap.

probeEventually the probe looks like this (picture)probe3

 

A capacitive soil humidity sensor: Part 2

capacitive74HC14_attinyIn a previous article I presented a simple way to read a capacitive moisture sensor with a simple RC generator.
In this post I will present a sensor with some added functionality that can be read through I2C. The circuit (figure) doesnt need much explanation: the RC generator we saw in the previous article and the two variable resistors in a voltage divide read by analogue inputs. The Attiny 45 (NOTE, it is NOT an Attiny25) is the heart, or rather the brains of the sensor. As the Attiny  functions as an I2C slave we will need the TinyWireS library. The library comes with some examples and one example was quite easy to rework to what I needed. The code is as follows.

#define I2C_SLAVE_ADDRES 0x4
#include <TinyWireS.h>//https://github.com/rambo/TinyWire
#ifndef TWI_RX_BUFFER_SIZE
#define TWI_RX_BUFFER_SIZE ( 16 )
#endif

volatile uint8_t i2c_regs[] =
{
	0x00,
	0x00,
	0x00,
	0x00,
};
// Tracks the current register pointer position
volatile byte reg_position;
const byte reg_size = sizeof(i2c_regs);

byte LDRvalue;
byte NTCvalue;
int MoistPulse;

/**
 * This is called for each read request we receive, never put more than one byte of data (with TinyWireS.send) to the
 * send-buffer when using this callback
 */
void requestEvent()
{
	TinyWireS.send(i2c_regs[reg_position]);
	// Increment the reg position on each read, and loop back to zero
	reg_position++;
	if (reg_position >= reg_size)
	{
		reg_position = 0;
	}
}

/**
 * The I2C data received -handler
 *
 * This needs to complete before the next incoming transaction (start, data, restart/stop) on the bus does
 * so be quick, set flags for long running tasks to be called from the mainloop instead of running them directly,
 */
void receiveEvent(uint8_t howMany)
{
	if (howMany < 1) { // Sanity-check return; } if (howMany > TWI_RX_BUFFER_SIZE)
	{
		// Also insane number
		return;
	}

	reg_position = TinyWireS.receive();
	howMany--;
	if (!howMany)
	{
		// This write was only to set the buffer for next read
		return;
	}
	while(howMany--)
	{
		i2c_regs[reg_position] = TinyWireS.receive();
		reg_position++;
		if (reg_position >= reg_size)
		{
			reg_position = 0;
		}
	}
}


void setup()
{
	pinMode(1, INPUT);
	TinyWireS.begin(I2C_SLAVE_ADDRESS);
	TinyWireS.onReceive(receiveEvent);
	TinyWireS.onRequest(requestEvent);
}

void loop()
{
	readSensors();
	/**
	 * This is the only way we can detect stop condition (http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=984716&sid=82e9dc7299a8243b86cf7969dd41b5b5#984716)
	 * it needs to be called in a very tight loop in order not to miss any (REMINDER: Do *not* use delay() anywhere, use tws_delay() instead).
	 * It will call the function registered via TinyWireS.onReceive(); if there is data in the buffer on stop.
	 */
	TinyWireS_stop_check();
}

void readSensors()
{
	LDRvalue = (analogRead(A2)) >>2; // max value is 1023/4=255 is 1 byte (FF) physical pin3=PB4=A2
        i2c_regs[0] = LDRvalue;
	NTCvalue = (analogRead(A3)) >>2; // max value is 1023/4=255 is 1 byte (FF) pin2=PB3=A3
	i2c_regs[1] = NTCvalue;
	//pulsepin= pin6=PB1
	MoistPulse = pulseIn(1, HIGH);
	i2c_regs[2] = highByte(MoistPulse); // or use = MoistPulse >> 8;
	i2c_regs[3] = lowByte(MoistPulse); // or use = MoistPulse & 0xFF;
}

I have called the pulseIn function with an integer rather than with a long. This means that you will have to choose a value for R3 that gives a reasonable range for the type of soil that you use. A range of say 0-200 uS is very reasonable. Once you have done that you can also add a timeout to the pulseIn function. This should be abt 2 times the pulselength you expect (but depends on the duty cycle). With regard to the two variable resistors, they are in pull up so their value is Rntc = Rseries/((1023/ADC) – 1));  For the NTC this could be substituted in a Steinhart Hart approximation

The code to call the values (and that is loaded onto the master arduino) is even simpler:

#include <Wire.h>
void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  for (byte i=0;i<4;++i){
  Serial.print("0x");
  Serial.println(readRegister(i),HEX); // print the character
}
Serial.println(" ");
    delay(1000);
  }

uint8_t readRegister(uint8_t regaddress)
{
	Wire.beginTransmission(4);
	Wire.write((byte)regaddress);
	Wire.endTransmission();
	Wire.requestFrom(4, 1);
	return Wire.read();


 delay(500);
}

This code only prints out the values, you still need to combine the LSB and MSB from the cycle time and e.g. switch a pump based on the value. You could do that with this function:

int combine (byte lsbv, byte msbv)
{
	int value = msbv << 8;
	value = value | lsbv;
	//value= msbv<<8 | lsvb;//if you want to do it in one go
	return value;
}

Don’ t forget that the I2C lines need pull-up resistors of 4.7-10k.

In a next article I will present the construction of the probe itself.