Electric Imp Weather Station



A while ago I started a project called Camille, it is a breakout board for an Electric Imp 001 and contains relays and other outputs. My Camille project is a bit on hold since I am not entirely sure what I want to do with it yet, or how I want it to be. Instead I started a new project, Vesper!


Vesper is a breakout board that will easily connect an Electric Imp 001 to the Sparkfun Weather Meter assembly. All you need to do is to plug the two RJ11 connectors into Vesper, connect it to a 5V power supply, do the obligatory Electric Imp blink-up, program the Electric Imp from the website, and you are ready to go. (source code for this will be released after I got boards assembled and tested everything)


To get some data out of the Electric Imp, that is also easy to use with other languages, I decided to use JSON, and so far it looks like this.

    [weatherstation] => Array
            [raingauge] => Array
                    [today] => 0
                    [dur1440min] => 0

            [windvane] => Array
                    [dir] => NW
                    [deg] => 315
                    [raw] => 56717

            [anemometer] => Array
                    [ms] => 0
                    [kmh] => 0
                    [desc] => Calm


    [voltage] => 3.269
    [temperature] => 24.0594
    [light] => 38777
    [rssi] => -46
    [online] => 1
    [lastping] => 0

Almost done

Not even am I almost done writing strange things, I am also almost done with the board! :D

As you see, the only thing missing are the terminals for the relays, and the board should be ready for its first little batch to see if everything is as it should be. So far it all seems to work on a breadboard, but I could have overlooked something on the actual board.

Smile to the photographer!


Velleman PS3005D fan upgrade


The problem

The Velleman PS3005D programmable dc lab power supply is, in my opinion, a overall good value item, but there are room for improvement. One of those improvements is most definitely the cooling fan! The stock fan does the job, and is also moving a pretty good amount of air, but it is quite noisy. So here I am going to show how I replaced mine with a high quality fan from Noctua.

The new fan

The new fan is a Noctua NF-R8 Redux 1800, which is a 80x80x25mm fan.

Important! The fan can’t be more than 25mm deep, or it won’t fit in! You also wouldn’t want a super low noise fan, since they tend to also move a lot less air, which could end up being a big problem.

2014-08-14 15.22.59 (Large) 2014-08-14 15.23.12 (Large)

2014-08-14 15.23.43 (Large) 2014-08-14 15.24.30 (Large)

Anyone who had a Noctua fan will notice it isn’t in the normal Noctua colors, which are very………. ‘different’ from other fans.


The first thing we need to do can’t come as a surprise, we need to get the cover off!

To get the cover off, simply take out the screws on each side and lift it up while tilting it a bit forwards.

2014-08-14 15.25.04 (Large)

Inside we find a few boards and a big transformer at the bottom, but to replace the fan we only have to take the board at the back out.

2014-08-14 15.27.33 (Large) 2014-08-14 15.28.01 (Large)


Notice, some of the connectors got hot-glue on them, carefully cut that off so you can get the connector off without pulling too much on it. The connectors without glue got a little lock, simply press the end closest to the wires while gently pulling to get those off.

2014-08-14 15.28.09 (Large) 2014-08-14 15.28.18 (Large)

Before we can take the board out, we need to cut the wire for the fan.

2014-08-14 15.30.15 (Large)

Before cutting it, gently pull on it until it won’t go any longer.

2014-08-14 15.30.33 (Large)


I decided to cut it here, just so I can use the fan for something else if I want that at some point. After cutting the wire you can take out the four screws on the back, and the whole assembly with fan and board will come out as one unit.

2014-08-14 15.30.59 (Large)

With the board out, next step is to take the fan off.

2014-08-14 15.32.19 (Large)

But first… Let’s see what this is! Hmm, good quality dc fan? Whatever… At least it was a decent place to save some money to keep the cost down.

2014-08-14 15.32.39 (Large)

To get the fan separated from the heatsink, simply loosen the nuts in each corner. And don’t lose the shakeproof washers!

2014-08-14 15.32.46 (Large)


If we take a look at the heatsink, it is actually a pretty clever design.

The heatsink is one big piece of aluminium, with some taps bend down. Those taps are directly in the path of the airflow and it seems to work pretty well too.

2014-08-14 15.36.07 (Large)



When putting the fan back on, pay attention to how it is rotated compared to the board. Putting it on like this makes the wires come out of the fan right next to where the wire in the power supply is located.

2014-08-14 15.37.15 (Large)


Put the shakeproof washers on and the nuts afterwards and tighten, but not over tighten them.

2014-08-14 15.41.14 (Large)


Put the assembly back in, and mount the fan with the screws that either came with the fan, or use the ones that held the original fan in.

Here you can also see why the fan can’t be any deeper than 25mm. There are only around 1mm between the capacitor and transformer.

2014-08-14 15.44.25 (Large)


The last thing we need, after connecting all the connectors again, is to connect the new fan to the wires the old was connected to.

2014-08-14 15.45.55 (Large)


Remote a bit of the insulation on both wires from the fan and power supply, and pre-tin them.

2014-08-14 15.47.16 (Large)


Put some heat shrink tubing over the wires and solder them together.

2014-08-14 15.49.41 (Large)


Finish off by shrinking the heat shrink tubing, and wonder what that yellow wires is, and why it is there.

The yellow wire is from the fan, and can be used to calculate how many rpm’s it is spinning at. I don’t need that yet, but just in case I get bored and suddenly decide I want to know how fast the fan is spinning, I am leaving it.

2014-08-14 15.53.08 (Large)


At the front of the power supply, you can pull a bit on the wire for the fan so it gets out of the way and hides under the metal rail.

2014-08-14 15.53.38 (Large)


I ended up with the yellow wire following the other wires to the front of the power supply too.

2014-08-14 15.53.50 (Large)

And that’s it! All you need to do now is to put the cover back on, and enjoy a nice and silent power supply!


Electric Imp: Faster device.isconnected() function


The usage

The device.isconnected() function returns a true or false to tell if the device/impee is connected.

The problem

If it is important you know if the impee is online and ready to receive commands, or is ready to send something right now, the build in function might give you problems. The problem is that the build in function first returns false when the server tried to contact the impee and it has timed out. This can take multiple minutes, but with a simple function you can make your own which is a lot faster.

Some code


devicePing <- 0;
device.on("ping", function(msg)
  devicePing = time();

function deviceOnline()
  if (time() - devicePing >= 5) return false;
  return true;


function ping()
  agent.send("ping", "");
  imp.wakeup(1, ping);

How to use

This code will make the impee send a “ping” message to the agent once every second. The agent will then save the time it received the message on.

To check if the device is online you now call deviceOnline(); instead of device.isconnected(); and it will return true or false, depending on if the agent received the ping message within the last 5 seconds or not. This way the device will only be offline for up to 5 seconds before the function will return false. The 5 seconds can most likely be set to something lower too, but it is plenty for what I use it for.

Using Openweathermap with Electric Imp


I have not yet found a use for this, but in case anyone else could use it, or maybe I could use it myself later, I am going to post the function here..

function openWeatherMap()
  local url = "http://api.openweathermap.org/data/2.5/weather?q=" + OPENWEATHERMAP_ZONE + "&mode=json&units=metric";
    local data = http.jsondecode(resp.body);
    if ("message" in data)
      server.log("OpenWeatherMap returned: " + resp.body);
      server.log("main.temp: " + data.main.temp);
      server.log("main.temp_min: " + data.main.temp_min);
      server.log("main.temp_max: " + data.main.temp_max);
      server.log("main.pressure: " + data.main.pressure);
      server.log("main.humidity: " + data.main.humidity);
      server.log("wind.speed: " + data.wind.speed);
      server.log("wind.deg: " + data.wind.deg);
      server.log("wind.var_beg: " + data.wind.var_beg);
      server.log("wind.var_end: " + data.wind.var_end);
      server.log("weather.main: " + data.weather[0].main);
      server.log("weather.description: " + data.weather[0].description);
      server.log("weather.icon: " + data.weather[0].icon);
      server.log("weather.id: " + data.weather[0].id);
      server.log("data.name: " + data.name);
      server.log("data.dt: " + data.dt);
      server.log("clouds.all: " + data.clouds.all);
      server.log("sys.country: " + data.sys.country);
      server.log("sys.sunrise: " + data.sys.sunrise);
      server.log("sys.sunset: " + data.sys.sunset);

This should return something like

2014-04-18 15:23:15 UTC+2: [Agent] main.temp: 10
2014-04-18 15:23:15 UTC+2: [Agent] main.temp_min: 10
2014-04-18 15:23:15 UTC+2: [Agent] main.temp_max: 10
2014-04-18 15:23:15 UTC+2: [Agent] main.pressure: 1011
2014-04-18 15:23:15 UTC+2: [Agent] main.humidity: 61
2014-04-18 15:23:15 UTC+2: [Agent] wind.speed: 4.1
2014-04-18 15:23:15 UTC+2: [Agent] wind.deg: 360
2014-04-18 15:23:15 UTC+2: [Agent] wind.var_beg: 310
2014-04-18 15:23:15 UTC+2: [Agent] wind.var_end: 60
2014-04-18 15:23:15 UTC+2: [Agent] weather.main: Clouds
2014-04-18 15:23:15 UTC+2: [Agent] weather.description: broken clouds
2014-04-18 15:23:15 UTC+2: [Agent] weather.icon: 04d
2014-04-18 15:23:15 UTC+2: [Agent] weather.id: 803
2014-04-18 15:23:15 UTC+2: [Agent] data.name: Kolding
2014-04-18 15:23:15 UTC+2: [Agent] data.dt: 1397821800
2014-04-18 15:23:15 UTC+2: [Agent] clouds.all: 75
2014-04-18 15:23:15 UTC+2: [Agent] sys.country: Denmark
2014-04-18 15:23:15 UTC+2: [Agent] sys.sunrise: 1397794132
2014-04-18 15:23:15 UTC+2: [Agent] sys.sunset: 1397846030

I hope anyone find a use for it. :)

Using TimezoneDB with Electric Imp


Something that can be useful to know when doing some kind of logging, error reporting, or what else it could be, is when it happened. The big problem with time is that it is not the same all over the world, it is not even an absolute offset since some regions got day time saving where the time is offset another hour. To make it even more difficult it is done at different times too… You could either take account for all that yourself, or have someone else do it for you… I am lazy, so I like have others doing things for me, so this is what I do.

Over at timezonedb.com you can create a free account, and then they will tell you what time it is at the location you would like to know more about. What we want is their API, which will return a timestamp with the unix time, and the offset to that, depending on the region you asked about.

In this example I want to use the time in Denmark, which is in Europe, and got Copenhagen as capital city, so I put in “Europe/Copenhagen”. If you are not sure what you should put in, or if you get an error, you can see the supported list here http://timezonedb.com/time-zones

TIMEZONEDB_KEY <- "xxxxxxxxxx";
TIMEZONEDB_ZONE <- "Europe/Copenhagen";
function timeZoneDB()
  local url = "http://api.timezonedb.com/?zone=" + TIMEZONEDB_ZONE + "&format=json&key=" + TIMEZONEDB_KEY;
    if (resp.statuscode == 200)
      local data = http.jsondecode(resp.body);
      if ("status" in data)
        if (data.status == "OK")
          TIMEZONE_OFFSET = data.gmtOffset.tointeger();
          server.log("TimeZoneDB > Time offset: " + TIMEZONE_OFFSET + " seconds.")
          server.log("TimeZoneDB returned: " + resp.body);

This code will contact the timezonedb api, and set TIMEZONE_OFFSET to the offset from the timestamp/unix time.

After having used this function, you can as an example use this code to show the time for the zone you asked timezonedb about.

local t = date(time() + TIMEZONE_OFFSET, 'l');
server.log(format("%02d:%02d:%02d", t.hour, t.min, t.sec));

This will hopefully make things a lot easier for you.

OLED + Electric Imp = <3


After reading this post http://www.smovs.dk/blog/2014/03/03/electric-imp-driving-a-small-oled-display/ I decided to try those displays myself too, and oh my do I like them!

To control the display you only need 3 wires. Power, GND and TX, so on the Imp it only takes up one pin.

My first try to just make it show something, was pretty much the same as on the blog post mentioned before. All it does is to tell the ssid it is connected to, and the signal strength.

2014-04-09 21.35.05-1

While making the bar graph I also learnt more about how to make white and black textures, so it is possible to first draw something, then put black over it to turn parts of it off again. In the bar I use this, because the bar is actually two rectangles, one white and one black, just behind it to make sure the bar can both go up and down again.

To make the display show this, I used this code

display <- hardware.uart12;
display.configure(9600, 8, PARITY_NONE, 1, NO_RX);

display.write("CL"); display.write(0x01); //Clear display

display.write("SF"); display.write(0); display.write(0x01); //Set font 6,10,18,51,120,123,0

display.write("CS0"); display.write(0x01); //Cursor off

display.write("SC1"); display.write(0x01); //Set graphics to white

display.write("TP"); display.write(0); display.write(0); display.write(0x01); //Move to collum 0 row 0
display.write("TT" + "SSID: " + imp.getssid()); display.write(0x00); // Write text

display.write("TP"); display.write(2); display.write(1); //Move to collum 2 row 1
display.write("TT" + "dB: "); display.write(0x00); // Write text

function progressBar(barX, barY, barHeight, barWidth, border, percentage)
  barSplit <- ((((barWidth-2)-(border*2))/100.0)*percentage).tointeger();

  display.write("SC1"); display.write(0x01);
  display.write("DR"); display.write(barX); display.write(barY); display.write(barX + barWidth); display.write(barY + barHeight); display.write(0x01);

  if (barSplit > 0)
    display.write("FR"); display.write(barX+border+1); display.write(barY+border+1); display.write(barX+1+border+barSplit); display.write(barY+1+border + barHeight-2-(border*2)); display.write(0x01);
  if (percentage < 100)
    display.write("SC0"); display.write(0x01);
    display.write("FR"); display.write((barX+border+1)+(barSplit+1)); display.write(barY+1+border); display.write((barX+barWidth)-1); display.write(barY+barHeight-(border*2)); display.write(0x01);

function updateDisplay()
  local wifiDB = imp.rssi() + 87;
  wifiDB = (87.0/100.0) * wifiDB;

  progressBar(49, 14, 8, 77, 1, wifiDB)

  imp.wakeup(0.1, updateDisplay);

This will then update the bar chart every 0.1 second.

i2c controlled amplifier


I have for a while wanted to have some speakers out over my terrasse, and my surround receiver got multiple zones, but what if I want different volume levels?

Timing could not have been much better, just a few days after I started looking around for small amplifiers I could mount a stepper to to control volume, or opto to simulate key presses, adafruit posted a new device… A little 20w class D amplifier, with i2c!!!

Next up was to find a way to remote control it, and as I had a few Electric Imp’s laying around, this was an obvious choice… Biggest problem with this was that there were no tutorial on how to do this, and with my totally lack of experience with i2c, I had to turn to the Electric Imp forum, and a few members came to the rescue!

To control the amplifier from an Electric Imp, I can now use this code

function setVolume(_volume) {

    local address   = 0x4B <<1;
    local volume = _volume;
    if (volume > 63)
        volume = 63;
    else if (volume < 0)
        volume = 0;

    hardware.i2c89.write(address, format("%c%c", volume>>8, volume&0xff));


And so far the only word I have found for this, is AWESOME! :D

3D printing timelapses


What is it?

After having finished my MendelMax2 enough to print with it, I decided to do so, and also make so I can make something I enjoy to watch… Timelapses!

First of, what is a timelapse movie? It is basicly just a video running faster than the frames per second it was captured at. The way I do it is to just take a picture every few seconds instead of the 24fps my camera normally would.

In this first video I set my camera to take a picture every 5th second, then merged them into a movie running at 24fps.

While this works, it is still difficult to see what is actually going on because everything is moving so fast, and the hotend is never at the same place either. To make up for that, you can have the microcontroller controlling the printer, also control the camera, and that is what this post is actually about.

How do I make timelapses like this?

The Camera

To be able to control my camera, I use some software called chdk. It will run alongside the original firmware in the camera, and give it a lot of extra features, where one of the features is how to remotely control it.

On the chdk site you find the instructions on how to put it on the sd card, and how to start it afterwards.

The camera I got is a Canon PowerShot A560, but the A570 is most likely a better choice because it also got focus and exposure lock, so it can trigger faster when receiving the signal to fire.


To make sure it wont run out of power, I also ordered a mains power supply for it, and this is also where I really like this camera. It got a connector for a power supply and a usb b-mini connector. In the software you can adjust if the camera should power off by itself and how long screen should stay on. In some of the newer camera’s I got (not canon powershot’s) I can not connect a power supply, the usb connector isn’t a standard one, and when I connect it the camera goes into file transfer+recharge mode and can’t be used for anything else than that while the cable is connected. In the settings, or lack of, I can’t decide if it should stay on either. So even when this Canon PowerShot camera is old, it seems to be better than some newer cameras from other manufacturers within the same price range.


One last thing I needed was a usb cable to put between the controller and camera, this was also easy to find on eBay, and I even found a good quality 5 meter cable.

The connections

2014-03-09 14.07.23 (Large)

The connection on the camera isn’t something that should give any problems, as it is just a normal usb b-mini connector. The tricky part is most likely how to connect it to the controller, so here it goes.

On the picture you can see a 4 wire female pin header connector connected to my Rumba board, which is the controller for my 3D printer. From left to right the pinout is 12V-GND-PIN4-ANALOG9. To trigger the camera to take a picture only GND and a 5V trigger pin is needed, but having the option to expand functionality later is always good to have.

What is left is to cut the usb connector off the usb cable (not the one going into the camera), and solder the wires from the pin header to the usb cable. A good thing would be to check polarity and not rely on the wire colors being correct, in my cable GND was RED and 5V was BLACK.

Trigger it!

After having connected the pin header to the usb cable, and enabled the remote function in chdk (check the instructions on the chdk site), all that is left is to make the controller trigger the camera to take a picture.

The way I do it is to simply use gcode to change one of the pins, in this case PIN 5.

M42 P4 S255
G04 P50
M42 P4 S0

Or even better!

With the last update I got into Marlin, it is possible to use


annd configure it to work with CHDK. It will then result in a seamless printing motion, with the camera triggering while the printer is moving.

This will set pin 4 to HIGH, which means it will be outputting 5V, it will then wait 50mS before setting it to LOW again (0V).

A thing I quickly noticed was that with my camera and the buffer in the controller, it would set the pin high about 5-8 seconds before the layer was actually done, the camera would then start to get focus and exposure lock. The printer would then finish the layer and get to the G04 P50 where it would wait and following set the pin low again. When the pin goes low the camera takes the picture, resulting in it taking a picture at the right time, even when not having manual focus and exposure lock.

2014-03-09 15.53.00 (Large)

Reading JSON from Electric Imp


After having some fun reading JSON with JavaScript, I also wanted to read values from my Electric Imp, but I ran into a problem which turned out to be very easy to fix, continue reading to find out what it was and how to deal with it.


First we have the JSON itself. What we are using here is nothing special and should be fairly easy to read with some not too complicated code. So, what do we want to read? We want something like this

	"name": "light",
		"connected": true,
		"deviceID": "deviceid"

With this we are able to tell what name we give the result, in this case “light”, because I am just going to use the light sensor to get some values to work with. Right after name we got result where the values from the light sensor is put.

After result we got coreInfo, this is actually from SparkCore where sensor readings are returned as JSON by default, so to keep my code simple and universal, I decided to just adapt it to my Electric Imp code too. Inside coreInfo we got connected which can show if the Impee is connected or disconnected (this example is not going to use that, but should be easy to add in)(this example now uses that), and last we got deviceID where we return the device id.

Agent code

To return the JSON we want, we use the Agent for the Electric Imp.

function requestHandler(request, response)
  response.header("Access-Control-Allow-Origin", "*");
  response.send(200, "{\"name\": \"light\",\"result\": \"" + lightUpdate + "\",\"coreInfo\": {\"connected\": " + device.isconnected() + ",\"deviceID\": \"" + deviceID + "\"}}");

deviceID <- "";
device.on("setDeviceID", function(msg)
  deviceID = msg;

lightUpdate <- 0;
device.on("updateLight", function(msg)
  lightUpdate = msg;

In here we got a bit of code to receive the light values from the Impee, and also the device id.

Device code

To send the values to the Agent we only need a few lines of code

function updateLight()
  agent.send("updateLight", hardware.lightlevel());
  imp.wakeup(1, updateLight);

agent.send("setDeviceID", hardware.getdeviceid());

and this should do the trick.


We now got got the Impee sending values to the Agent, and the agent set up to give the reply we want. What we need next is a bit of JavaScript to read that reply and parse the JSON so we can put it into fields on a web page.

		<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type">

		<script type="application/javascript">
			function loadJSON()
				var data_file = "https://agent.electricimp.com/xxxxxxxx-xxxxx"; //Insert link to your Agent here
				var http_request = new XMLHttpRequest();
					// Opera 8.0+, Firefox, Chrome, Safari
					http_request = new XMLHttpRequest();
				catch (e)
					// Internet Explorer Browsers
						http_request = new ActiveXObject("Msxml2.XMLHTTP");
					catch (e)
							http_request = new ActiveXObject("Microsoft.XMLHTTP");
						catch (e)
							alert("Something went wrong. :/");
							return false;

				http_request.onreadystatechange = function()
					if (http_request.readyState == 4)
						if (http_request.status == 200)
							var jsonObj = JSON.parse(http_request.responseText);

								document.getElementById("device").innerHTML =  jsonObj.coreInfo.deviceID;
								document.getElementById("function").innerHTML =  jsonObj.name;
								document.getElementById("result").innerHTML = Math.round((jsonObj.result/65535) * 100) + "%";
								document.getElementById("device").innerHTML =  "offline";
								document.getElementById("function").innerHTML =  "&nbsp;";
								document.getElementById("result").innerHTML = "&nbsp;";

						setTimeout("loadJSON()", 1000);

				http_request.open("GET", data_file, true);


				font-family:"Trebuchet MS", Arial, Helvetica, sans-serif;

			#devices td, #devices th
				border:1px solid #98bf21;
				padding:3px 7px 2px 7px;

			#devices th

		<title>Electric IMP and JSON</title>

		<h1>Electric IMP and JSON</h1>

		<table id="devices" class="devices">
				<th width="300px">Device</th>
				<th width="200px">Function</th>
					<div id="device">&nbsp;</div>
					<div id="function">&nbsp;</div>
					<div id="result">&nbsp;</div>

And this should do just that…

However, as mentioned in the beginning of this post, I had a problem reading from the Electric Imp agent. With the exact same code I could read from the SparkCore API just fine, so I started digging a bit. The browser console I got “No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”, and it turned out that I had to send an extra header when sending the reply from the agent, to be able to use it on other pages.

To fix this I simply had to set

response.header("Access-Control-Allow-Origin", "*");

Just before sending the reply from the Electric Imp Agent. A little simple problem, if you know what is wrong. :)


Yes, a bit dramatic headline, but better safe than sorry… Using this code will expose your agent url to whoever access the page, so if you use it for other things you might want to add some kind of password/token system for that part, find a way to pass the return to the page without using the direct url, or simply not use this at all.

Spark core, first code…


As you might have noticed from a previous post, I got a Spark Core.

I haven’t done much with it yet, but what I have done is to make it able to turn pins high/low, using their web api.

TCPClient client;
byte server[]  = { xx, xx, xx, xx };

char tempStr[16];

void setup()
    //Register our Spark function here
    Spark.function("SWITCH", pinSwitch);

void loop()

int pinSwitch(String command)
   int state = 0;
   //find out the pin number and convert the ascii to integer
   int pinNumber = command.charAt(1) - '0';

   //Sanity check to see if the pin numbers are within limits
   if (pinNumber < 0 || pinNumber > 7)
       return -1;

   // find out the state of the led
   if(command.substring(3,7) == "HIGH")
       state = 1;
   else if(command.substring(3,6) == "LOW")
       state = 0;
       return -2;

   // write to the appropriate pin
   pinMode(pinNumber, OUTPUT);
   digitalWrite(pinNumber, state);
   return 1;

unsigned long lastSync = 0;
void nodeSync()
    if ((millis() - lastSync < 3600000  && lastSync != 0) && millis() >= lastSync) return; //Only check once every hour, unless we havent checked yet, or if time since overflow of millis is less than last time we checked
    lastSync = millis();


    if (client.connect(server, 80))
        RGB.color(255, 0, 0);
        String tsData = String(Spark.deviceID());

        client.println("GET /nodeSync.php?spark=" + tsData + " HTTP/1.1");
        client.println("Host: server.com");
        client.println("Connection: close");

        while (client.available()) //Read what is returned from the server
            char c = client.read();
            if (millis() - lastSync > 500) break; //Read for maximum 500ms, then stop reading



This code actually does a bit more than just changing the pins… I made a file for the different nodes to synchronize with. Calling this file with the id of the node makes the server do the appropriate calls to the node again, making the pins go high/low according to the database. This happens both on initial start of the node and then again every 60 minutes (or every 3600000 millisecond).


To use this code for something else you will have to fill in the server ip and change “Host: server.com” to be the same as yours too.

Go to Top