Tuesday 15 December 2015

Two external screens on a Microsoft Surface Pro 4

I could not get more than one external screen on a Surface Pro 4 to work. The docking-brick has two mini-display ports, there is one display port on the side of the tablet. But regardless of the combination, more than one screen wouldn't work.
That was with the usual "right click on desktop" mehtod to get access to the screen properties.
The only option there was to duplicate the screen to one of the external monitors.

All screens show up ok in the device manager. But in the win10 screen settings ony the main screen appeared, along with an option to duplicate the output to screen 2 or 3. Rather pointless in this scenario.

All screens working ok now
Solution:
Go to the traditional control panel and find the settings for screen resolution there.
The two external screens shown in black.
The external screens are show as "disconnected"

They look normal when the Desktop has been extended to use these screens. This has to be done for both external screens.
Then you can arrange them as needed:
Three screens in different orientations
These settings do survive a reboot, but may be destroyed when using the Win10-style screen settings window.

EDIT: 2015/12/17 This issue appears to be resolved in the build 1511.

EDIT: 2016/01/08 With three active screens, windows does not seem to store the screen settings. The two external screens are recognized, but not used.
As a workaround, we disable the Surface 4's own screen. That seems to result inm a stable configuration. When undocked, the internal screen can be used as usual without intervention.

Friday 11 December 2015

Installing sound drivers on the Microsoft Surface 4 Pro from the command line

The SCCM Win10 OS deployment for our brand new Surface 4 pro PCs refused to find the drivers for the Realtek audio drivers through windows update.

The drivers can be downloaded (at the time of writing) here.

After a lot of attempts with the deprecated rundll32 setupapi method, we found that the following method worked:

 c:\temp\SmartSoundOED>pnputil -i -a IntcOED.inf  
 Microsoft-PnP-Hilfsprogramm  
 Verarbeitungsinf.:      IntcOED.inf  
 Der Treiber konnte auf einem Gerät dieses Systems installiert werden.  
 Das Treiberpaket wurde erfolgreich hinzugefügt.  
 Veröffentlichter Name:      oem46.inf  
 Versuche gesamt:       1  
 Anzahl erfolgreicher Importe: 1  
 c:\temp\SmartSoundOED>  

Same thing with the HDXSSTM.inf file from the HDAudio directory.
So on our SCCM server, we added a package and a task in the task sequence to run pnputil for the two drivers.

Thursday 10 December 2015

Espressif ESP-8266: minimal configuration for running the ESP-12e module

I am working on a project where I haven't quite decided on some of the details, so I wanted a module that breaks out a lot of the ESP8266's pins, just to have as many options available as possible.

Here is also a 5 minute video about it.

The ESP-12e module seems like a good choice, with the added benefit of having 4MBytes of flash memory.
ESP-12e module from Banggod
So I ordered a pack of three from Bangood for just under 8 Euros. After quite a long wait they arrived and I had to take them to the workbench for a quick test drive, right away.

Odd stuff

A few things are a bit odd about these modules:
  • The silkscreen is a very poor print quality
  • The ADC pin is labelled ADG
  • The GPIO labels are a mess. Eg: There is no GPIO0 (this is labelled GPIO6 instead)

Where's GPOI0?
Todo: try flashing LEDs on all GPIOs to compare against NodeMCUs IO table


Basic configuration

So after a little experimentation, this turned out the most basic configuration:
Basic config for ESP-12e
I plan to run this without a circuit board, so I'll simply shorten GPOI15 to ground and connect the "Chip Power Down" Pin (CH_PD) to 3.3V. 

The Module came preinstalled with some AT-firmware, I didn't much care about.

Flashing new firmware

To program new firmware, GPOI0 (which for some reason is GPIO6 here) needs to be connected to ground. I am a huge fan of NodeMCU, so I flashed that to the module.
Ground GPIO6 (=GPIO0) to flash firmware via UART

This goes without saying

Connecting the serial-usb converter is unspectacular. Just the usual RXD-TXD / TXD-RXD thing. And don't forget to connect the ground wires.
Connecting the USB2Serial converter



Wednesday 25 November 2015

Using node.dsleep() in NodeMCU to extend battery lifetime in ESP8266 projects

For some applications, like checking sensors, the ESP8266 does not need to run permanently with all it's bells and whistles on. The datasheet claims 10uA when in deep sleep mode.
NodeMCU, currently my preferred firmware, does support that sleep mode, but I've never tried using it. Mainly because it is a pain to modify the ESP-01 which used to be my perferred module.

Olimex MOD-WIFI-ESP8266-DEV

With the Olimex modules, I aquired a while ago, trying this out is a piece of cake. Both the reset-pin and GPIO 16 are freely accessible. The ESP8266 wakes up from deep sleep on a falling edge on the reset pin. This signal does not necessarily need to come from GPIO16, but can also be generated externally.

The brown wire does it all

NodeMCU syntax

It is explained in detail here. Basically it is:

node.dsleep(Time-In-uSecs , option)

Where "option" can be 0-4. But I don't quite understand the "0" option yet.
If you send it to sleep for 0 useconds, you'll need to trigger the wakeup from an external source.

Power considerations

In my experiments, the running module took around 70mA from it's 3,3V supply.
In deep sleep mode, the module draws a little less than 0.8mA which is great and will run the system for months with a good 18650 rechargeable battery. Still it is quite a bit more than the 10uA from the data sheet.
Looking at the Olimex datasheet, two things come to mind:
  • The SPI Flash memory (W25Q16BVSSIG) has a 25-50 uA standby current and can peak to 25mA when active.
  • There is a power LED with a 2k resistor that is constantly on and will probably account for most of the current
Another interesting option to node.dsleep() ist option 4, which leaves WiFi disabled when waking up. This saves a lot of power while the system can read sensors or process other information. I've seen it draw around 12mA in this mode.

Video

I've also documented that in a short video on my youtube channel.

Todo

Try the same with an ESP-12 that has no LED

Wednesday 18 November 2015

Microsoft surface pro 3 USB overcurrent protection vs iPhone 6s

At work, I got a new iPhone 6s the day before yesterday. This morning the battery was down to about 18% because I used it to track a 13km run last night, listened to some podcasts and played ingress on the way back from walking the kids to school.
So when I plugged the phone into the docking station of my Surface Pro 3 (i5 model), a message window came up:
Poorly translated error message
The message "Stromüberspannung am USB-Anschluß" literally means "Currentovervoltage on USB port". Ouch, this sounds so wrong!
I suppose it means to say that the over current protection has kicked in and the port needs to be reset.
This worked and the iPhone started charging/synching.

Next day: measure current


The next day I brought my USB meter. The phone was around 30% when I took this picture. The PC didn't complain. So I suppose yesterday's current was even higher than that.

A little over 1A from an USB3.0 port
According to Wikipedia that is out of specs for an USB3.0 port:
Source: Wikipedia
Over time the current drops to acceptable levels:

  • At 70% current is down to 0.6A
  • At 95% current drops to 0.45A
  • At 100% it is down to 20-70mA

All of this is within specs. But it seems that a well discharged phone draws too much current.

23.11.15:
My iPad Air charges at 0.46A from the same USB port, while it takes 2.2A from the original charger. That's what I'd expect. The 6s charges at 1A from that charger, although rumor has it that it can charge at 2A, I have yet to see proof of that.

27.11.15:
Again the phone was down at 7% and the same message came up. This time I had my USB meter with me. 1.3A is clearly too much.What still puzzles me: When I connect it to my 2A iPad charger, it only takes 1A.

Next: Try other phone



Tuesday 17 November 2015

Flying the Cheerson Sanlianhuan CX-10C camera drone

This blog article is a companion to this youtube video on my channel.

Despite all their limitations, I like the Cheerson minidrones. They are inexpensive, rugged and fit into any jacket's pocket. So they're ideal to take with you on a walk and are great to teach the kids a thing or two about flying. Being a licensed pilot myself (well - for paragliding, that is ), I simply enjoy the occasional flight.

I have both the

  • CX-10 which used to be the world's smallest drone for some time

and  the

  • CX-10A which is a headless version of the above. The headless mode (tap the left stick 2x) takes a lot processing power off the pilot's brain and makes flying easier for the kids. 

We had a little fun with those two in the office and of course one of the first questions was:

"It doesn't have a camera, does it?"
"Naah, no way. That thing can never possibly carry a camera"

Little did I know that only a few months later, the world's smallest camera drone hit the market.
Once the price was down below the magic (German customs regulation) 22€ mark, I ordered one straight from the PRofC. It also has a CE mark on the box, which means it won't get stuck in customs for safety / EMI reasons.

Unboxing

Last week I was delighted to find that CX-10C drone in my mail.
Contents of the package

Setup

It is a little higher that the CX-10 / CX-10A and significantly heavier. I inserted a FAT32 formatted 2GByte micro SD card. - The card's contacts have to face UP when inserting.
PowerBanks are very handy to charge the CX-10C

I charged the battery from my XIAOMI power bank which has the added benefit that it turns off once the charging current drops below (TODO: measure current) mA. The charger does not appear to offer any protection against overcharging. (TODO: double check this) 
To my amazemt, the charge current drops to zero then the LED goes out. So the battery doesn not overcharge.
In all other blogs, the battery capacity is quoted as 120 mAh. On my box it clearly says: 80 mAh
Looks like it only has a 80mAh lipo cell

Flying

I took it to a nearby park for a first test. The first thing I noticed was the sluggish climb rate. The CX-10/A responds far more aggressively to the throttle. Pitch and roll are very low in the default ("junior") mode. That is great to get stable video recordings, but the copter will be blown away even in light winds.
During flips, the drone loses about 1 to 1,5 meters of height. In the older, lighter models this was very well compensated. It is still amazing that it still works, given the increased mass of the thing.

Still pictures

The stills are obviously not great.

Unprocessed still. - Original size

Video recordings

See my youtube video for some of my recordings.
Videos appear over-sharpened to me, which makes the 640x480 resolution appear better than it actually is. If the sun is low on the horizon, colours are a bit washed out.
It is amazingly good in low / artificial light.


Pros:

  • low cost (below 22€ on ebay)
  • CE mark
  • light weight / portable
  • safe - won't hurt too much if you accidentially hit someone
  • ok video quality for the money


Cons:

  • No camera gimbal, so any front/back/side movement will make the viewer seasick.
  • No headless mode. That would make it easier to concentrate on shooting video footage.
  • Poor flight-time vs charge-time ratio
  • No proper charging circuit
  • handles a bit sluggish / poor weight vs power ratio

Final word:
Yes, you want that. It's fun and it's cheap.

Monday 2 November 2015

Building the DSO138 portable oscilloscope

A friend of mine once said:
"All it takes to assemble an electronic kit is a trained monkey."
While the construction of this kit did in fact not take much brains, it would take a very nimble fingered monkey to do the SMD soldering.
I couldn't have done it without a little help from my magnifying lamp
My somewhat yellowed, late 80s Ersa 230 - 15W iron's conical tip shouldn't have been any wider, but was ok for both the resistors and the IC.
The through-hole components were not a problem at all. I just misplaced two components and the solder is very hard to get out of the through-plated holes. So better double-check before soldering.

The instructions are nicely printed in colour and, easy to follow and include full schematics.

As an alternative, for just one extra euro, there is a version available that has all the SMD components in place already.
Very neat measurement readout
This thing is not a replacement for a fully featured scope. Still I'll try to get it into a 3d printed enclosure like this one, to use it as a portable scope.
Equipment needed:

  • Soldering iron 15W / conical tip
  • Fine tweezers
  • Desondering pump / braid (just in case)
  • Solder 1,0mm or less
  • Small soft wire cutters
  • Magnifying lamp (if you're over 40)

Bottom line: Fun little project for just over 20 bucks. Not really worth the effort if you already have a scope.

Saturday 24 October 2015

Using the ESP8266 as a WiFi range extender

This blog article refers to my YouTube Video you find here.
It shows how an ESP8266 module (like this one) can be used as a (rather unreliable) WiFi range extender.

Overview of the setup

Beside an ESP8266 module, you need to:

  • download the modified firmeware here and flash it to your module 
  • copy the DNS forwarder script from here to your module
  • add a route to the 192.168.4.0 subnet to your default gateway (i.e. usually  your WiFi dsl/cable router)
  • attach the module to your WiFi network and run it in StationAP mode:
 wifi.setmode(wifi.STATIONAP)  
 wifi.sta.config("YOURSSID","YOURWIFIPASSWD")  
 tmr.alarm(0, 500, 1, function()  
     if wifi.sta.getip()==nil then  
      print("Connecting to AP...")  
     else  
      tmr.stop(1)  
      tmr.stop(0)  
      print("Connected as: " .. wifi.sta.getip())  
     end  
   end)  
 cfg={}  
    cfg.ssid="intarwebs"  
    wifi.ap.config(cfg)  

  • connect another device to the "intarwebs" SSID. If you want to really use that, you should encrypt that side as well. Here is how.
The disconnects from the Wifi Router appear to be related to  big packets and/or heavy traffic. It has been suggested that it might be a power issue, but neither with the scope, nor with the Fluke 87V's min/max function I was able to detected a significant voltage drop.
I have captured the traffic with wireshark, but could not make sense of it yet. My best guess at the moment is that with a big TCP windows size, the module runs into a buffer size problem or that it is busy for too long on the "left" side. The module only has one radio to serve both connections, so unlike your typical router, it can't forward a continuous stream of packets.



Sunday 27 September 2015

Building the QRP Pixie v3 ham radio transceiver

When I saw this kit on Banggood, I just couldn't resist. A 7 MHz / 40m ham radio transceiver for just under 4€ is certainly worth a try.
The kit came with very sparse instructions, partly in Chinese. It had a circuit diagram, a parts list and enlarged PCB silkscreen with it.
I arranged the components on my desk in the order of the BOM. This made sense as it starts with the passive components.
Bits'n pieces

I was a bit unsure about the inductor values, but found a nice calculator here.
The soldering was painless and took about an hour.
The assembled 40m Pixie
For the initial tests I soldered a 9v clip to the legs of the power socket. My power supply caused a bad 50Hz hum, so I had to go for battery power.
The Pixie prefers battery power
To check the output, I connected a 50 Ohms resistor (came with the kit) to the output and had a look at it with my scope.

Transmitter output
By the looks of it, I can't expect perfect spectral purity. But it is QRP, so I can let it get away with it. The signal will most likely pass an ATU anyway.

My friend CP had printed me this case from thingiverse. A perfect fit:

The enclosure designed by egil
Next thing was listening in: With a random length of wire (abt. 3m) I could hear some stations from all over Europe very faintly but good'nuff to follow the CW QSOs. I heard all of them at the same time. There is no narrow band filter. So be prepared to use your ears/brain to do the signal processing.
There is also no volume control and the "RIT" is not accessible with this enclosure. (This THING addresses the RIT issue).
The Pixie circuit is as basic as it can get, while the nice key/phone/power/antenna sockets feel like luxury to me.

73 de dl9set

PS: You must be a licensed radio ham of the appropriate license class to operate this transceiver.

Wednesday 23 September 2015

Generic UDP proxy for NodeMCU / ESP8266 - Simple LUA DNS proxy

For a project that has been in the works for quite some time, I need a ESP8266 module to act as a DNS proxy. Other than on my very popular CaptiveIntraweb project, that simply lies to all DNS requests, I need real DNS lookups this time.

Getting my head slowly around the event driven nature of NodeMCU, the code turned into a very compact, generic UDP proxy or forwarder.
The script is completely unaware of the structure of the data and could be used to proxy all sorts of UDP data.

Here is my code:

 -- Simple DNS Proxy  
 -- 20150923 by Andy Reischle  
 -- Blog: www.AReResearch.net  
 -- Vids: www.youtube.com/AReResearch  
 --  
 -- Uses googles dns server 8.8.8.8  
 -- change to whatever suits you  
 cu=net.createConnection(net.UDP,0)  
 cu:on("receive",function(cu,c)   
   -- print("Got a reply")  
   s:send(c)  
   end)  
 s=net.createServer(net.UDP)  
 s:on("receive",function(s,d)  
   -- print ("Got a request!")  
   cu:connect(53,"8.8.8.8")  
   cu:send(d)   
   end)  
 s:listen(53)  

The ESP-module is connected to a WiFi AP, of course. The IP address of the ESP module is 192.168.1.74 and will be different, depending on your home DHCP server.

I can query DNS information through the module now:
me@raspberrypi:~$ nslookup
> server 192.168.1.74
Default server: 192.168.1.74
Address: 192.168.1.74#53
> www.areresearch.net
Server:         192.168.1.74
Address:        192.168.1.74#53

Non-authoritative answer:
www.areresearch.net     canonical name = ghs.google.com.
ghs.google.com  canonical name = ghs.l.google.com.
Name:   ghs.l.google.com
Address: 173.194.65.121
>
The corresponding tcpdump also looks very clean:

me@raspberrypi:~$ sudo tcpdump -i eth0 port 53
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
23:39:08.416736 IP noname.43027 > noname.domain: 56537+ A? www.areresearch.net. (37)
23:39:08.422009 IP noname.46122 > fritz.box.domain: 4560+ PTR? 58.1.168.192.in-addr.arpa. (43)
23:39:08.426857 IP fritz.box.domain > noname.46122: 4560* 1/0/0 PTR noname. (88)
23:39:08.428198 IP noname.45680 > fritz.box.domain: 56651+ PTR? 74.1.168.192.in-addr.arpa. (43)
23:39:08.430620 IP fritz.box.domain > noname.45680: 56651* 1/0/0 PTR noname. (88)
23:39:08.432969 IP noname.38314 > fritz.box.domain: 15794+ PTR? 1.1.168.192.in-addr.arpa. (42)
23:39:08.435987 IP fritz.box.domain > noname.38314: 15794* 1/0/0 PTR fritz.box. (89)
23:39:08.480105 IP noname.domain > noname.43027: 56537 3/0/0 CNAME ghs.google.com., CNAME ghs.l.google.com., A 173.194.65.121 (101)

While the rest of the project still requires a lot of tinkering, this little piece of the puzzle works nicely.


Tuesday 22 September 2015

Changing the ASG Time Navigator TCP Port for MS-Exchange compatibility

At work we're in the process of upgrading from exchange 2007 to 2013. The windows guys got the job done with the usual little issues.
One unexpected issue occured when everything seemed to be ready to migrate the users to the new servers:
We were unable to install the Time Navigator Agent because TCP port 2525 was already in use by the exchange server as explained here.
We did not want to run into problems with future updates/patches on the Exchange server, so the TINA agent had to move over and use a different TCP Port.

That turned out to be easier than expected:
Time Navigator mostly relies on the services file of the operating system

Our backup server ist a CentOs machine, so the file is:
/etc/services

The  Exchange Servers are Windows servers, of course, so the services file is located at:
C:\WINDOWS\system32\drivers\etc

The backup server uses the catalog name as a service entry. You'll find something like:
yourcat          2525/tcp        # Time Navigator (yourcat)
yourcat-msg      2526/udp        # Time Navigator (yourcat)

On the Exchange Server, tina seems to be the generic name of the service
tina            2525/tcp        # Time Navigator (tina)
tina-msg        2526/udp        # Time Navigator (tina)

The default for the UDP Port is 2526 and there is absolutely nothing wrong with having the TCP protocol using the same port number. So TCP 2526 is the port of choice.

We changed:
/etc/services
to
yourcat          2526/tcp        # Time Navigator (yourcat)
yourcat-msg      2526/udp        # Time Navigator (yourcat)
(where "yourcat" is your catalog name)

and
C:\WINDOWS\system32\drivers\etc
to
tina            2526/tcp        # Time Navigator (tina)
tina-msg        2526/udp        # Time Navigator (tina)

That only did the trick partially. The web interface wouldn't connect to the catalog. So after some investigations, I found out that the web interface does not rely on the services file.

The ports are hard wired in:
/usr/Atempo/AtempoWebInterfaces/apache-tomcat/webapps/YOURCAT/WEB-INF/config/TinaConfiguration.xml

Change the ports in the <catalogs> and the <webRestore> section.
Restart Tina's Tomcat:
/usr/Atempo/AtempoWebInterfaces/rc_startup_aws.sh restart

brings the web interface back with it's full functionality.

On our Solaris and Linux clients, all it took was changing the entry in the services file, as well. Then restart the tina daemon. That's it.

Friday 18 September 2015

New CaptiveIntraweb release V3 - ESP8266 / NodeMCU based captive portal

After a few hours of brushing things up, I released a new version of my CaptiveIntraweb on  my GitHub repo.
Apart from a few bug fixes, an all-new init.lua now does the Wifi Setup, compiles the LUA files and starts the servers. It also features an option to prevent the TCP and UDP servers from starting.

I did most of the development on my new, very user friendly V3 NodeMcu Lua WIFI Development Board I got directly from the PRC from Banggood. That board has 4MByte of flash memory. (Yes. I mean MBytes here, not MBit)

Looks a lot like a ESP-12E module on the board

If you don't know about CaptiveIntraweb, here is the original video from May 2015, although quite a bit of progress has been made since then.

With the new CaptiveIntraweb  loaded, the module startup now looks like this:
 ---------------------  
 Setting up WiFi AP...  
 Done.  
 ---------------------  
 Flash size is 4096 kBytes.  
 File system:  
  Total : 3360 kBytes  
  Used : 124 kBytes  
  Remain: 3236 kBytes  
 ---------------------  
 Compiling LUA files...  
 No need to compile   dns-liar.lua  
 No need to compile   server.lua  
 Compiling done.  
 ---------------------  
 Send some xxxx Keystrokes now to abort startup.  
 Will launch servers in 5 seconds...  
 > ---------------------  
 Starting HTTP Server  
 HTTP Server listening. Free Heap:    13080  
 Starting DNS Server  
 DNS Server listening. Free Heap:    10008  
 ---------------------  

Tuesday 8 September 2015

Arduino and ESP8266 - part 2 - The web thermometer

In the previous video, I've shown various options to connect an ESP8266 module to an Arduino board. Now it is time to turn that into something (sortof) userful.

Watch this video to see how I build a web connected thermometer.



The program is a bit particular in that it wants AT-firmware 0.9.2.2 to run stable. I have tried the latest AT firmware but had no luck and didn't invenstigate any further. It's default baud rate of 9k6 is slow enough for a SoftwareSerial connection.

There are no surprises in the schematic diagram:



Here ist the code:


 /* ====== ESP8266 Web Thermometer Demo ======  
  * Print out temperature from TMP36 sensor  
  * on analog-in 3  
  * (Modified Aug 28, 2015 ARe)  
  * ==========================  
  *  
  * Change SSID and PASS to match your WiFi settings.  
  * The IP address is displayed to serial upon successful connection.  
  *  
  * modified by Andy Reischle (www.AReResearch.net)  
  * based on:  
  * Ray Wang @ Rayshobby LLC  
  * http://rayshobby.net/?p=9734  
  */  
 #define SSID "MYWIFI"   // change this to match your WiFi SSID  
 #define PASS "sorrywonttell" // change this to match your WiFi password  
 #define PORT "80"      // using port 80 by default  
 char buffer[BUFFER_SIZE];  
 // using Software Serial for connection to ESP  
 // Use the definitions below  
 #include <SoftwareSerial.h>  
 SoftwareSerial esp(10,11); // used pins 10, 11 for software serial   
 #define dbg Serial  
 // By default we are looking for OK\r\n  
 char OKrn[] = "OK\r\n";  
 byte wait_for_esp_response(int timeout, char* term=OKrn) {  
  unsigned long t=millis();  
  bool found=false;  
  int i=0;  
  int len=strlen(term);  
  // wait for at most timeout milliseconds  
  // or if OK\r\n is found  
  while(millis()<t+timeout) {  
   if(esp.available()) {  
    buffer[i++]=esp.read();  
    if(i>=len) {  
     if(strncmp(buffer+i-len, term, len)==0) {  
      found=true;  
      break;  
     }  
    }  
   }  
  }  
  buffer[i]=0;  
  dbg.print(buffer);  
  return found;  
 }  
 void setup() {  
  // assume esp8266 operates at 9600 baud rate  
  // change if necessary to match your modules' baud rate  
  esp.begin(9600);  
  dbg.begin(9600);  
  dbg.println("begin.");  
  setupWiFi();  
  // print device IP address  
  dbg.print("device ip addr:");  
  esp.println("AT+CIFSR");  
  wait_for_esp_response(1000);  
 }  
 bool read_till_eol() {  
  static int i=0;  
  if(esp.available()) {  
   buffer[i++]=esp.read();  
   if(i==BUFFER_SIZE) i=0;  
   if(i>1 && buffer[i-2]==13 && buffer[i-1]==10) {  
    buffer[i]=0;  
    i=0;  
    dbg.print(buffer);  
    return true;  
   }  
  }  
  return false;  
 }  
 void loop() {  
  int ch_id, packet_len;  
  char *pb;   
  if(read_till_eol()) {  
   if(strncmp(buffer, "+IPD,", 5)==0) {  
    // request: +IPD,ch,len:data  
    sscanf(buffer+5, "%d,%d", &ch_id, &packet_len);  
    if (packet_len > 0) {  
     // read serial until packet_len character received  
     // start from :  
     pb = buffer+5;  
     while(*pb!=':') pb++;  
     pb++;  
     if (strncmp(pb, "GET /", 5) == 0) {  
      wait_for_esp_response(1000);  
      dbg.println("-> serve homepage");  
      serve_homepage(ch_id);  
     }  
    }  
   }  
  }  
 }  
 void serve_homepage(int ch_id) {  
  String header = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: close\r\nRefresh: 5\r\n";  
  String content="";  
 // read in TMP36 at Analog 3 port  
  int reading = analogRead(3);  
  float voltage = reading * 5.0;  
  voltage /= 1024.0;   
  float temperatureC = (voltage - 0.5) * 100 ;  
  Serial.print(temperatureC); Serial.println(" degrees C");  
  content += "Temperature is ";  
  content += temperatureC;  
  content += "C <br />\n";  
  header += "Content-Length:";  
  header += (int)(content.length());  
  header += "\r\n\r\n";  
  esp.print("AT+CIPSEND=");  
  esp.print(ch_id);  
  esp.print(",");  
  esp.println(header.length()+content.length());  
  if(wait_for_esp_response(2000, "> ")) {  
   esp.print(header);  
   esp.print(content);  
  } else {  
   esp.print("AT+CIPCLOSE=");  
   esp.println(ch_id);  
  }  
 }  
 void setupWiFi() {  
  // try empty AT command  
  esp.println("AT");  
  wait_for_esp_response(2000);  
  // set mode 1 (client)  
  esp.println("AT+CWMODE=1");  
  wait_for_esp_response(2000);   
  // reset WiFi module  
 /*  
  esp.print("AT+RST\r\n");  
  wait_for_esp_response(3000);  
  delay(5000);  
  */  
  // join AP  
  esp.print("AT+CWJAP=\"");  
  esp.print(SSID);  
  esp.print("\",\"");  
  esp.print(PASS);  
  esp.println("\"");  
  // this may take a while, so wait for 5 seconds  
  wait_for_esp_response(5000);  
  esp.println("AT+CIPSTO=30");   
  wait_for_esp_response(1000);  
  // start server  
  esp.println("AT+CIPMUX=1");  
  wait_for_esp_response(1000);  
  esp.print("AT+CIPSERVER=1,"); // turn on TCP service  
  esp.println(PORT);  
  wait_for_esp_response(1000);  
 }  

I have made two modifications to the code:

  • To keep the Arduino's original debugging facility, I kept the hardware UART for that purpose and defined a "software serial" port on pins 10 and 11. The suggested firmware version defaults to 9600 baud, so speed is not an issue.
  • The other change is that I nicked a few lines of code from Adafruit to replace the original output

Thursday 27 August 2015

Level converters - How to safely connect an Arduino to a ESP8266 module



This is the companion blog article to my video on YouTube.
A second part with a practical application will follow.

Option 1: Bidirectional N-type Mosfet level shifter

This is my favourite "no worries" solution. These modules provide 4 bidirectional lines. Enough for most of my little projects and more than enough for a serial connection between an Arduino Uno and a ESP-01 module.


These level converters can be obtained for cheap from here.

Option 2: Voltage follower

Not bidirectional but also a very clean solution is this voltage follower. The output level follows the input signal but only to the point when it reaches the supply voltage. I.e. 3V in this case.

The popular 2n2222a transistors will serve the same purpose and can be bought here.


Option 3: Zener clamp

This is a great option if you want a reliable solution with a minimum of components. The Zener diode clamps down the voltage on the 3V side of the resistor. (Output signal shown in green here.)

Here is a link to a set of zener diodes.



Option 4; Voltage divider

By far the cheapest option for a quick hack. The classic voltage divider. It does not provide any additional protection against voltage surges, but where those are not to be expected, you'll easily get away with that simplest of circuits.
Resistors are dirt cheap and you should always have some available. Here is a very basic set.

Tuesday 18 August 2015

Problems on windows 2008R2 production server following August 2015 patches

As a followup to this post, two of the August 2015 updates apparently fix the same issue, causing problems on one of our servers.

While in July the patches were:
KB3067505 and KB3057154

This time it is:
KB3060716 and  KB3071756

With these patches installed, a hot folder mechanism refused to work more than  once. The actual mechanism behind it still remains in the dark at the moment. Looking at the security bulletins, the problem appears to center around a privilege escalation bug.

Removing these two patches brought everything back to normal.


Monday 10 August 2015

Windows 10 (nearly) broke my Intel 4 Series Express graphics adapter


After an otherwise smooth transition from windows 8.1 to  Win 10 on my Dell E6400, OpenGL applications stopped working.

Stellarium relies on OpenGL
My graphics adapter apparently does not support openGL any more. It is an:
"Intel 4 series Express Chipset Family" adapter that has gone out of active support for quite a while.

After some failures, I found a surprisingly simple solution:
This Win7 driver from the Intel download center installed without any issues and brought OpenGL back at an (for this system) acceptable speed.
OpenGL is back - and so are the stars.

While a slightly newer installer (Win7Vista_64_151719.zip) refused to run on Win10, this one (Win7Vista_64_151717bb.zip) did.
I will probably have to prevent windows from updating that driver in the future.

20150824 Adendum:
The sound output of the docking station wouldn't work either. Replacong the IDT audio driver with the standard high-definition audio driver fixed that.

Friday 17 July 2015

Problems accessing long UNC paths on EMC VNX filer from Windows Server2008R2 after Update July 2015

After the latest set of patches from Microsoft had been installed on our production servers (Win 2008R2 Server)  we ran into problems accessing subdirectories of shares with long UNC names in our EMC VNX Filer.

The issue must be caused by one of the following patches:
KB3077657
KB3075516
KB3074886
KB3072633
KB3072630
KB3070738
KB3070102
KB3069392
KB3068457
KB3067903
KB3067505
KB3065987
KB3065822
KB3057154

The effect is that users can navigate to any UNC ressource when klicking their way through windows explorer. The same UNC path pasted into the address field causes an error.
VB Scripts accessing those ressources also fail. So does sending a PDF file (located in a subdirectory of a user's home drive) through AcrobatReader's send function.

I will investigate which of the updates causes the problem as soon as possible.

Edit 20150717 / 9:05h: Windows Server 2012R2 does not exhibit the problem.

Edit 20150717 / 11:13h: Removed all of the above form one of our 2008R2 terminal servers. Still no joy. Will remove OfficeUpdates next.

Edit 20150717 / 14:33: Temporarily solved by making the full path to the target directory browseable. Example: \\myserver\myshare\allhomes\myhome\somedir\someotherdir
Typing that path into Windows explorer resulted in an error. "allhomes" was not readable by the client. Making that readable fixed the user's problems.
Strangely enough \\myserver\myshare\allhomes\myhome worked without the modification.

Edit 20150717 / 17:32: We're still scratchig our heads about this. Our terminal servers still had the problem after uninstalling all of the above KBs. Making the whole path readable helped.
While another highly production-critical server was OK after removing them (and reboot).

Edit 20150720: We'll stick with the workaround: Make the whole path browseable. I'm not quite happy with that, but too much time has gone into that already.

Edit 20150721: Applied patches on another production machine. Also resulting in access probems. (Detail will follow)

Edit 20150722 / 14:50
Result:
EMC does not seem to have anything to to with our production problem. We're running a production-critical piece of software (and: yes, we have two them, of course) on a win2008r2 server . The software manufacturer came back to us this morning with new info:
The following patches must not be installed:
Security Update for Windows Server 2008 R2 x64 Edition (KB3067505) 
Security Update for Windows Server 2008 R2 x64 Edition (KB3057154) 

That still does not explain the initial problem we had on the terminal servers. That never should have worked in the first place. But the timing was too perfect to pass as coincidence.

Wednesday 8 July 2015

The LiPo Charger that wants to burn down your house


For a tiny LiPo package, I needed a charger.
Sounds like an easy one? I beg to differ.

Rather than reinventing the wheel I thought it was a good idea to get some tiny, ready made USB charger. A suitable circuit with a MCP73831 should come cheap enough from the PR of C. For around €2.50, I thought I could expect just that.
Wrong again.

I found one that was advertised as: 3.7V Lipo Battery USB charger JST plug 500ma output. It has a charge control LED that comes up when the battery is fully charged. - Sounds good. It arrived a few weeks later.

Just to be on the safe side, I took my meter (thou shalt check voltages) and was surprised that the USB-side seemed to be shorted to the charging side of the circuit. The meter read 5V on the charging connector. Way beyond safe for LiPos.

So two minutes a little prying later, I was in. And stunned.

Inside the plug

What did they do there? Is there any design rule not violated by this piece of ****? A 2.4 Ohms SMD resistor can't possibly pass for a LiPo charging circuit. I mistook it for a short.
Carefully tracing the circuit (because my initial impression just had to be wrong), this turned out to be the schematic diagram:


This "charger" is outright dangerous. I can't even remotely meet the proper charging conditions.
I have no idea where the "3.7V" and the "500mA" in the product description might come from. Possibly from the fact that some USB ports are limited to 500mA and that the nominal voltage of a LiPo cell is 3.7V.
And what are all those unused solderpads for? Maybe the original design idea was good and some electrical engineering genius found a way to cut the cost. At the expense of a few burnt down houses.

I suppose the idea might me to babysit the charger and the pack and wait for the LED to come on. Then disconnect the pack immediately. - That just won't work for me.


Watch my rant about this piece of **** on YouTube.




Thursday 2 July 2015

Second (successful) attempt to route IP packets with ESP8266

Now that one was a piece of cake:
As suspected /app/include/lwipopts.h overruled the file I modified previously.

So with a 
#define IP_FORWARD 1
in there, the the module started forwarding packets

Ping connectivity table
PING 192.168.1.50 192.168.1.75 192.168.4.1 192.168.4.3
192.168.1.50 n/a n/a n/a YES
192.168.1.75 YES n/a n/a n/a
192.168.4.1 YES n/a n/a YES
192.168.4.3 YES n/a YES n/a



So I now could ping the Laptop (ouch: forgot to disable the firewall first) from the mobile device and vice versa.
Here is the caveat:
  • I need a static route from the Laptop to the "StationMode" interface of the ESP8266. The cooler way to do that is on the default router.
Up to now this is an easy one for the ESP module. Both subnets are directly connected, so the routing decision is not really that hard. With very little tweaking, this could already be used  as an extremely simple range extender working at layer 3.
To daisy-chain / mesh more of these, I need to supply routing information to LWIP. It is not too obvious where to do that in the code or what it takes to add commands to manipulate routes through LUA.

Wednesday 1 July 2015

First (failed) attempt to route IP packets with ESP8266

In every other comment on my previous projects, someone brought up the topic of mesh networking with ESP8266 modules. Gooooogling the topic, I couldn't find a project that had made into a stable release. (Drop me a line in the comments if you found/have one)

Taking things nice & slow, I started with the following setup:




Ping connectivity table
PING 192.168.1.50 192.168.1.75 192.168.4.1 192.168.4.3
192.168.1.50 n/a n/a n/a n/a
192.168.1.75 YES n/a n/a n/a
192.168.4.1 YES n/a n/a YES
192.168.4.3 NO n/a n/a n/a

So as expected, the ESP8266/NodeMCU does not forward IP packets. I had a peek at the NodeMCU sources and made the following change to /app/include/lwip/opt.h:

 /**  
  * IP_FORWARD==1: Enables the ability to forward IP packets across network  
  * interfaces. If you are going to run lwIP on a device with only one network  
  * interface, define this to 0.  
  */  
 #ifndef IP_FORWARD  
 // #define IP_FORWARD           0  
 #define IP_FORWARD           1  
 #endif  

I rebuilt the firmware, flashed it to a ESP Module and:

FAILED. No changes to the module's routing behaviour.

If anyone is more familiar with the code, don't hesitate to leave a comment.


Next Steps:

  • Get packet forwarding to work
  • Routes? What routes? (There is a hook for those in later versions of LWIP. Backporting possible?)



PS:
Another search of the source code shows that there is another place that sets IP_FORWARD: /app/include/lwipopts.h - I'll try that next.







Saturday 27 June 2015

CaptiveIntraweb: New firmware, new scripts & new videos

Providing Android compatibility (while IOS workes always worked) turned out to be easy in the end. So it is time for a 1.0 release of the project files:

  • Find an all-in-one package with scripts, html-pages and firmware in the master-branch of my github repository.


  • In this video, you see me setting up the Olimex MOD-WIFI-ESP8266-DEV module. As described earlier these modules come with 2MBytes of flash memory.


  • While in that video, you see me using the portal on an IOS and an Android device to show the now fixed Android support.


Monday 22 June 2015

CaptiveIntraweb now running on Olimex MOD-WIFI-ESP8266-DEV

I finally found the time to try the new firmware on one of the two Olimex MOD-WIFI-ESP8266-DEV boards.

  • I decided to mount the headers upside-down to have the silkscreen readable when I have it plugged into the breadboard.
  • Flashing the firmware worked as expected. (GPIO0 / Pin21 hardwired to GND - That's ok, trust me.)
  • Formatting the i2c flash file system tool longer than expected. That worried me for a second or two.


The board then came back:
 NodeMCU 0.9.5/AReResearch build 20150318 powered by Lua 5.1.4  
 lua: cannot open init.lua  
 > file.format()  
 format done.  
 >   
 ----------------------------  
 No files found.  
 ----------------------------  
 >   
 > r,u,t=file.fsinfo() print("Total : "..t.." bytes\r\nUsed : "..u.." bytes\r\nRemain: "..r.." bytes\r\n") r=nil u=nil t=nil  
 Total : 1513781 bytes  
 Used : 0 bytes  
 Remain: 1513781 bytes  
 >   

Woooooha! 1.5MBytes of free space! Just think of the possibilities!

Next thing was to try the CaptiveIntraweb scripts. So I uploaded the files, ran "ap-mode.lua" to set the WiFi parameters and had another look at the remaining file system space:

 ----------------------------  
 about.htm    : 511 bytes  
 ap-mode.lua   : 89 bytes  
 counter.txt   : 1 bytes  
 dns-liar.lua  : 1352 bytes  
 index.htm    : 459 bytes  
 init.lua    : 46 bytes  
 instruct.htm  : 1075 bytes  
 kg-small.png  : 6037 bytes  
 server.lua   : 3144 bytes  
 ttt.htm     : 19471 bytes  
 wumpus.htm   : 13825 bytes  
 ----------------------------  
 Total file(s)  : 11  
 Total size   : 46010 bytes  
 Total : 1513781 bytes  
 Used : 50702 bytes  
 Remain: 1463079 bytes  

Still plenty of space remaining. I then restarted the module and:

Beauty! No trouble at all. (see edit below)

Edit: I might have a minor problem writing the counter.txt file to the local file system. The games loaded unreliably, so I commented out the code for the counter and the system was sometimes back to the expected speed. I couldn't find a change in the nodeMCU firmware to account for that. - This needs a closer look.

Two OLIMEX MOD-WIFI-ESP8266-DEV boards in the mail

When a CaptiveIntraweb experimenter from Chicago pointed out that he had problems with Olimex ESP8266 modules, we looked into the problem and it seemed like a file system related issue.
The cool thing is that these modules come with 2MByte of i2c flash, rather than the usual 512k. And that might just be the source of the problem.

I wasn't aware these modules existed and immediately ordered a pair. Despite the fact that the German postal service is on strike, the modules arrived on Saturday.

Nice silkscreen 

The weekend was rather busy, so I couldn't test drive the modules. From the first look, I am impressed by the build quality and the nicely readable silkscreen. So impressed in fact, that I'll mount the headers upside-down to have an unobstructed view of the print.

One thing I didn't like at first glance was that to change to flash mode, I need to change soldered jumpers. With the number of tries I need to get things right, I considered mounting a switch.
A closer look at the schematic revealed this:
Now that's nice circuit design! I can still use a jumper cable on the breadboard to tie GPIO0 to GND manually to reflash the firmware. 

I will try that tonight and let you know how it went.
It went better than I expected. See here.

Wednesday 17 June 2015

Installed new build environment for ESP8266 firmware

It seems about time to refresh the firmware for my CaptiveIntraweb portal. There are three issues I hope to address:

  • I couldn't get my i2c OLED to work with the February build of NodeMCU. My firmware is based on that.
  • A user from Chicago reported problems with Olimex modules. I ordered a pair of them because they'd make ideal platforms for throwies with their 2MByte (as opposed to 512kByte) i2c flash.
  • It all seems to be open source now, so I can redistribute the firmware freely. Although it looks like a blend of quite a few flavours of open source licenses.

What I have done up to now:

  • Installed the espressif ubuntu image from here
  • Installed the build environment with pfalcon's excellent esp-open-sdk
  • Downloaded NodeMCU sources from the master branch

I have made the following changes to the code:

  • In ./app/include/user_config.h around line 50, comment in #define LUA_NUMBER_INTEGRAL to reduce overall memory requirements
  • Changed line 10 in ./app/include/user_version.h to #define NODE_VERSION    "NodeMCU 0.9.5/AReResearch", so I can see I am on my homebaked version when the module boots up
  • In ./app/include/lwip/app/dhcpserver.h add #define USE_DNS somewhere (around line 54)


I have not changed the Buffer size:

Line 545 in ./app/lua/luaconf.h is currenlty left at:
#define LUAL_BUFFERSIZE         ((BUFSIZ)*4)

This had caused problems with the dns-liar.lua script in the past. If it still does, I will change that.
With regards to the 2MByte Olimex modules, the code defaults to "auto" for the flash size. But I'll have to wait for the modules to arrive to check that out.

Next step: try it on an esp-01 module
That worked ok.
Next step: try it on an Olimex MOD-WIFI-ESP8266-DEV

Edit: 20150622

Wednesday 20 May 2015

Mini WiFi-Throwie with CR123A

Last night I finally found the time to fire up the soldering iron and try the CaptiveIntraweb with a CR123A cell.
As expected, this worked without any issues. From the data sheet, I expect a run time of approx. one day, although I haven't tried that yet.
Again the discharge rate of  around 70mA ist significantly higher than the 20mA mentioned in the data sheet. From this page it looks like the Panasonic cell is the best choice for high discharge currents.
A bit of tape (Kapton tape should be the ideal choice) to told it together and that's it.
Just don't forget to recover the throwie after the battery is drained and recycle it properly.

I will have the video on my Youtube Channel as soon as I have it ready.


Tuesday 5 May 2015

Flashing & running the ESP-201 module

Up to now I only had access to ESP-01 modules. The ESP-201 has a few extra pitfalls.
To flash the firmware, connect the following pins:



  • GND / VCC / RXD / TXD the usual way
  • CHIP_EN to 3.3V
  • GPIO00 to GND
  • GPIO02 to 3.3V
  • GPIO15 to GND

To run the newly flashed firmware:

  • GND / VCC / RXD / TXD the usual way
  • CHIP_EN to 3.3V
  • GPIO00 to 3.3V
  • GPIO02 to 3.3V
  • GPIO15 to GND
Apart from the CHIP_EN, the GPIOs might be left floating when they are marked 3.3V in the table above.
I haven't done anything fancy yet. Just flashed it with NodeMCU and tried a couple of my scripts. I can't wait to try stuff on the additional GPIOs.

I bought the module here.

Monday 4 May 2015

Schematic diagram for the CaptiveIntraweb Wifi-throwie

My CaptiveIntraweb has been featured on Hackaday and received a lot of attention lately.
Although it could hardly be any simpler, here is the schematic diagram for it:

Here are the components:

Here is the link to the original video: https://www.youtube.com/watch?v=fQM-GHY6VJ8
And here the GitHub Repository: https://github.com/reischle/CaptiveIntraweb

Wednesday 29 April 2015

Failed making the smallest WiFi throwie ever

It all looked so simple. I had the video equipment set up and rolling. Assembled the (to my knowledge) first ever WiFi-Throwie. But those in the know might spot the problem right away in this picture.

Yes, the CR2032 battery totally caved in under the 70mA load of the ESP8266 / ESP-01 module.
And I should have known.
The typical discharge rate for a CR2032 is 0.2mA. I need about 350 times more, well knowing this wouldn't last for long.
I then learned the hard way that the internal resistance is obviously way too high.
TI has a document here, where they tried discharge currents beyond the recommended 15mA maximum. But they wouldn't go beyond 30mA. This blog article also confirms that.
So it's back to 18650 rechargeables. Or quite possibly CR123 if size matters.

EDIT; Ordered a CR123 and suitable battery holder today. I'll keep you posted.

Wednesday 22 April 2015

ESP-01 Wifi softap drops

Today I noticed Wifi connectivity loss at regular intervals of 25 seconds.
A friend of mine played with a CaptiveIntraweb prototype and repeatedly lost connectivity.
This sucks because Apple IOS devices will close the captive portal screen when the WiFi network disappears.

The problem is clearly visible on the Fluke Airwatch tester:


I haven't had this before, so the first thing is to look into power problems. At the time of testing, I had the ESP8266 running on a top quality 3.7V 18650 lithium cell with a 1N diode in series to get rid of 0.6V. That is well within the module's specs.
More research is required....

Edit 10150424:
It clearly was not a power problem. The module ran on this high quality lithium battery for another day (about 45hrs in total). The problem disappeared after a while. I haven't found any problems since.

Friday 17 April 2015

Joined forces with CPMalek to further refine the CaptiveIntraweb

I am very pleased to announce that today CPMalek joined as collaborator for the CaptiveIntraweb project on GitHub. CP will do away with the "early 90s" look & feel of my HTML code.
CaptiveIntraweb runs on an ESP-01 module (ESP8266)

We see CaptiveIntraweb as an art project exploring the feasibility of wifi throwies. The use as highly localized web service should open new possibilities using well established technologies.

Extremely limited RAM/Flash ressources and the high power requirement of an access-point make this an interesting challenge.

Wednesday 15 April 2015

Scanning for i2c devices on ESP-01 / ESP8266 modules running NodeMCU / LUA

Trying to get my OLED module to work on one of my ESP-01 modules, the first thing I did today was making sure the ESP-01 "sees" the OLED.
I had found an excellent little LUA script here: http://www.esp8266.com/viewtopic.php?f=19&t=1049#p6198 the user goes by the name "gwizz". Kudos to him (gareth@l0l.org.uk)

 dofile("i2c-autoscan.lua")  
 Scanning all pins for I2C Bus device  
 Device found at address 0x3C  
 Device is wired: SDA to GPIO0 - IO index 3  
 Device is wired: SCL to GPIO2 - IO index 4  
 >  

This works a treat and helps me to avoid silly mistakes. - Highly recommended.

Monday 13 April 2015

ESP8266 / ESP-01 NodeMCU playing the Imperial March

Looking at the NodeMCU documentation, I came across the PWM feature of the Firmware. And one of the fundamental laws of electronics is: "If it can make noise, it has to play the Imperial March."
Gooooogling didn't show any results, so it might not have been done before. We can fix that.

I found a rather nice Arduino sketch by Andre Tagliati here and ported that over to LUA for the ESP8266. So all the credits for the artistic work converting the original score go to Andre.
The schematic is rather simple:
I had found a piezo speaker in the junk box. That connects to GPIO2. I added a 100 Ohms resistor just because of a gut-feeling that at high frequencies the current might be too high. It works without that just as well.
The rest of the circuit is exactly the same as always.
Now for the interesting bit - The LUA script:

 --Ported to LUA from https://gist.github.com/tagliati/1804108 (Andre Tagliati)  
 --by AReResearch (www.areresearch.net) Andy Reischle  
 --Port index4=GPIO2  
 speakerPin = 4;  
 gpio.mode(speakerPin,gpio.OUTPUT)  
 --speaker connected port  
 --Tone table  
 t={}  
 t["c"]=261  
 t["d"]= 294  
 t["e"]= 329  
 t["f"]= 349  
 t["g"]= 391  
 t["gS"]= 415  
 t["a"]= 440  
 t["aS"]= 455  
 t["b"]= 466  
 t["cH"]= 523  
 t["cSH"]= 554  
 t["dH"]= 587  
 t["dSH"]= 622  
 t["eH"]= 659  
 t["fH"]= 698  
 t["fSH"]= 740  
 t["gH"]= 784  
 t["gSH"]= 830  
 t["aH"]= 880  
 --frequencies for the tones we're going to use  
 --used http://home.mit.bme.hu/~bako/tonecalc/tonecalc.htm to get these  
 function beep(pin, tone, duration)  
 local freq = t[tone]  
 print ("Frequency:" .. freq)  
 pwm.setup(pin, freq, 512)  
 pwm.start(pin)  
 -- delay in uSeconds  
 tmr.delay(duration * 1000)  
 pwm.stop(pin)  
 --20ms pause  
 tmr.wdclr()  
 tmr.delay(20000)  
 end  
 --Play it  
   --for the sheet music see:  
   --http://www.musicnotes.com/sheetmusic/mtd.asp?ppn=MN0016254  
   --this is just a translation of said sheet music to frequencies / time in ms  
   --used 500 ms for a quart note  
   beep(speakerPin, "a", 500)  
   beep(speakerPin, "a", 500)  
   beep(speakerPin, "a", 500)  
   beep(speakerPin, "f", 350)  
   beep(speakerPin, "cH", 150)  
   beep(speakerPin, "a", 500)  
   beep(speakerPin, "f", 350)  
   beep(speakerPin, "cH", 150)  
   beep(speakerPin, "a", 1000)  
   --first bit  
   beep(speakerPin, "eH", 500)  
   beep(speakerPin, "eH", 500)  
   beep(speakerPin, "eH", 500)  
   beep(speakerPin, "fH", 350)  
   beep(speakerPin, "cH", 150)  
   beep(speakerPin, "gS", 500)  
   beep(speakerPin, "f", 350)  
   beep(speakerPin, "cH", 150)  
   beep(speakerPin, "a", 1000)  
   --second bit...  
   beep(speakerPin, "aH", 500)  
   beep(speakerPin, "a", 350)  
   beep(speakerPin, "a", 150)  
   beep(speakerPin, "aH", 500)  
   beep(speakerPin, "gSH", 250)  
   beep(speakerPin, "gH", 250)  
   beep(speakerPin, "fSH", 125)  
   beep(speakerPin, "fH", 125)  
   beep(speakerPin, "fSH", 250)  
   tmr.delay(250000)  
   beep(speakerPin, "aS", 250)  
   beep(speakerPin, "dSH", 500)  
   beep(speakerPin, "dH", 250)  
   beep(speakerPin, "cSH", 250)  
   --start of the interesting bit  
   beep(speakerPin, "cH", 125)  
   beep(speakerPin, "b", 125)  
   beep(speakerPin, "cH", 250)  
   tmr.delay(250000)  
   beep(speakerPin, "f", 125)  
   beep(speakerPin, "gS", 500)  
   beep(speakerPin, "f", 375)  
   beep(speakerPin, "a", 125)  
   beep(speakerPin, "cH", 500)  
   beep(speakerPin, "a", 375)  
   beep(speakerPin, "cH", 125)  
   beep(speakerPin, "eH", 1000)  
   --more interesting stuff (this doesn't quite get it right somehow)  
   beep(speakerPin, "aH", 500)  
   beep(speakerPin, "a", 350)  
   beep(speakerPin, "a", 150)  
   beep(speakerPin, "aH", 500)  
   beep(speakerPin, "gSH", 250)  
   beep(speakerPin, "gH", 250)  
   beep(speakerPin, "fSH", 125)  
   beep(speakerPin, "fH", 125)  
   beep(speakerPin, "fSH", 250)  
   tmr.delay(250000)  
   beep(speakerPin, "aS", 250)  
   beep(speakerPin, "dSH", 500)  
   beep(speakerPin, "dH", 250)  
   beep(speakerPin, "cSH", 250)  
   --repeat... repeat  
   beep(speakerPin, "cH", 125)  
   beep(speakerPin, "b", 125)  
   beep(speakerPin, "cH", 250)  
   tmr.delay(250000)  
   beep(speakerPin, "f", 250)  
   beep(speakerPin, "gS", 500)  
   beep(speakerPin, "f", 375)  
   beep(speakerPin, "cH", 125)  
   beep(speakerPin, "a", 500)  
   beep(speakerPin, "f", 375)  
   beep(speakerPin, "c", 125)  
   beep(speakerPin, "a", 1000)  
   --and we're done \ó/  
The beep() function is the only moderately interesting bit. I had to insert a tmr.wdclr() to avoid problems with the watchdog timer. The rest is pretty much what Andre had prepared. Just in a LUA flavour.

The videos will appear on my Youtube channel shortly.
Here is the first video: https://youtu.be/dlnj3u-Tj3A