Adding X-Clacks-Overhead

For a long time on my to-do list, but postponed due to perceived complexity: adding X-Clacks-Overhead.

Now I got around to looking into what is actually involved, and… It’s not all that convoluted. For nginX it a single line to be added in a server, location or http block.

add_header X-Clacks-Overhead "GNU Terry Pratchett" always;

Next up was finding the right file in the Yunohost setup of nginX: I did find a single (default) sites-available, but no sites-enabled.

All configuration is put in the conf-directories, where I put the additional header in the conf of the main site in the server section.

vi /etc/nginx/conf.d/mysite.tld.conf

Now first see that the header is not there before reloading nginX:

~# curl -IL mysite.tld
 HTTP/1.1 302 Moved Temporarily
 Server: nginx
 Date: Sat, 28 Dec 2019 11:23:13 GMT
 Content-Type: text/html
 Content-Length: 154
 Connection: keep-alive
 X-SSO-WAT: You've just been SSOed
 Location: https://mysite.tld/yunohost/sso/?r=aHR0cHM6Ly9zYW55aS5ubC8=

See? No X-Clacks header. Reload nginX…

service nginx reload 

… and have a look at the headers again:

~# curl -IL mysite.tld
HTTP/1.1 302 Moved Temporarily
Server: nginx
Date: Sat, 28 Dec 2019 11:25:52 GMT
Content-Type: text/html
Content-Length: 154
Connection: keep-alive
X-SSO-WAT: You've just been SSOed
Location: https://mysite.tld/yunohost/sso/?r=aHR0cHM6Ly9zYW55aS5ubC8=
X-Clacks-Overhead: GNU Terry Pratchett

It now shows at the bottom line.

Actually the X-Clacks-Overhead is only added to the HTTP 1.1 headers. The HTTP 2 headers omit the header at the moment. After rereading the config, I added the header to the server listening at port 80 over HTTP 1.1; it gets forwarded to port 443 over HTTP 2. That block did not have the header. After adding the header there as well, the HTTP 2 headers show the X-Clacks-Overhead as well:

~# curl -IL mysite.tld
 HTTP/2 404 
 server: nginx
 date: Sat, 28 Dec 2019 11:33:18 GMT
 content-type: text/html
 content-length: 162
 x-sso-wat: You've just been SSOed
 set-cookie: SSOwAuthRedirect=;; Path=/yunohost/sso/; Expires=Thu, 01 Jan 1970 00:00:00 UTC; Secure; HttpOnly; SameSite=Lax ;;
 strict-transport-security: max-age=63072000; includeSubDomains; preload
 content-security-policy: upgrade-insecure-requests
 content-security-policy-report-only: default-src https: data: 'unsafe-inline' 'unsafe-eval'
 x-content-type-options: nosniff
 x-xss-protection: 1; mode=block
 x-download-options: noopen
 x-permitted-cross-domain-policies: none
 x-frame-options: SAMEORIGIN
 x-clacks-overhead: GNU Terry Pratchett

One difference between the two header blocks, is that the HTTP1.1 block is capitalized, whereas the HTTP2 block is not. Fine with me 🙂

So, two points of my mental to-do list, one for the Clacks itself and one for moving it from a mental to-do list to a physical (of some sort) to-do list.

Print this entry

Wireless floor heating thermostat

We installed infrared floor heating film. It has not yet been connected, lacking a thermostat. My idea from the start was to use Arduino or compatible to build the thermostat myself. There were some reasons for that: it was cheaper than a ready built device, more flexible and an excellent reason to get started with Arduino.

So, to prevent any misunderstandings: although the floor is not wired yet, it is not wireless. The thermostat will be wireless on one end, the end to the user interface. From the thermostat to the floor it wires all the way down.

In the mean time the parts have arrived:

  • ESP32, the brains of each thermostat
  • Relays, to actually switch on or off the infra red film
  • 10k NTC’s are already under the floor, together with the film itself

The separate functions I need/want to integrate are easily found, and integrating them went quite quickly at first. The result was almost what I needed, lacking only the sensor for ambient temperature. And it only would work in the wrong order. Which functions are they and what went wrong in the first iteration?

  • Temperature measurement
  • Thermostat setting
    • On the one hand ambient temperature: the temperature we find comfortable in the room
    • On the other hand the floor temperature: the floor temperature is not allowed to raise above 29 degrees Celsius
  • Switching a relay based on measured temperature and thermostat setting
  • Accessible via WiFi on the internal domotica network

As stated, each separate function got its examples for Arduino as well as, fewer, for ESP32. I ended up with a loop that:

  • Connect to WiFi
  • Shows a web interface to turn on or off the relay
  • Measures the temperature on pushing the on or off button
  • Actually switching on or off based on measured floor temperature

So the thermostat would not interfere with the relay until a button was pressed. The loop should work in reverse order:

  • Check relay state
    • if off, measure ambient temperature and compare to thermostat value
    • if on, measure floor temperature and compare to set maximum temperature
  • Depending on above, switch the relay state or keep as is
  • Connect to WiFi for a minute
  • Show the web interface
  • Allow the thermostat to be set
  • Return to above

The next step is to have a domotica server serving the thermostat interface, and the ESP querying the domotica server every now and again for changes. That way, less time is spent broadcasting a web interface via WiFi, improving power efficiency and security. At first it will be a stand alone setup though.


What connections/pins do I need? Which pins are they on the board?

  • Ralay; the relay needs three pins:
    • Ground;
    • VCC, the relay needs 5V, but it sits on a PCB with additional logic to let it switch with 3.3V supplied;
    • Switching signal, 3.3V as well; that also drives the process towards the “floor is to hot”- or the “room is not warm enough”-branch.
    • I’m free to use any digital-out pin for this
  • Floor sensor; the floor sensor needs three pins as well:
    • Ground;
    • VCC, any, as long as it is known and constant. I’ll use 3.3V as supplied by the ESP32;
    • Sensor pin;
    • The sensor-pin; any analog-read pin will do. It will read the voltage ‘halfway’ the ground-NTC-sensor-resistor-VCC series. The read voltage is then converted to a temperature.
  • Ambient sensor; just like the floor sensor:
    • Ground;
    • VCC;
    • Sensor pin / analog read.

I have some trouble converting the pin-examples I find on the Net to the actual pins on my ESP32. The names of the pins in those pictures are just a few letters different from the names of the pins silkscreened on the PCB. The pins that are supposed to be called ‘sensor VP’ and ‘sensor VN’, are called ‘SP’ and ‘SN’, and are moved one pin because I got an extra 3.3V pin on one side and extra GND pin on the other side.

Most of the pins are called Gnn, with nn being a number ranging from 0 to 36, in seemingly random order. G0 is between G2 and G4, and then G17 and G16 come before G5. G could stand for GPIO, and sometimes they match the notation on the images I find online. Of course not all options for each pin can be silkscreened on the tiny PCB. With my currently limited knowledge of Arduino programming, it does not help understanding the code I find in the wild. How should I assign a name to an input or output? Lets just try it with simple programs, building and understanding from there instead of hacking something together and hoping for the best: there is no lack of basic tutorials, it just takes some time to apply them to my ESP32-board, test its behaviour and measure electric properties of pins.

Test with ‘touch’ pin

While reading up on the pins and how to interact with them, I come across an explanation of ‘touch’ pins. They presumably can be used as input by just touching them. I’ll make sure to test that and keep it in mind as another way of setting the temperature.

Actually writing a simple program myself has taught me more than reading five of them and then flinging together something complicated to see what sticks. Namely:

  • Arduino is touchy about casing. Be sure to write analogRead, not analogread or Analogread: it won’t be recognized.
  • Same goes for semicolons. Forget one, and the compiler complains that there is an unexpected } instead of a ;
  • Prototyping is fast once you got something you understand that is working.
  • Use the right function for the type of input you’re working with. In case of the touch pins:
    • My first guess was using analogRead. It ‘works’, giving 12 bit high values (4095) when licking the connected wire or touching either the 3.3V or the 5V pin, 0 when connecting with GND. Using my fingers, the most intuitive way to interact with touch interfaces, gives fluctuating readings. Above 2000 when I draw blood with the pin, slowly descending values when I let go of it. Conclusion so far: it might work, but only when using more than one button and reading all of them to infer which one actually has been touched (and educating users not to touch more than one button at a time).
    • Next up was digitalRead. That gave 1 instead of 4095, 0 just as analogRead, and random 1 or 0 in between.
    • The actual function to use for touch pins is touchRead. It gives quite low (10+/-10) readings when touching the pin, and around 60 when not touching. Surprisingly, it gives 1 when touching 3.3V and 0 for GND,
    • The wire tastes as if there is some current on the line, my multimeter gives 0.7V as the amount between ground and GPIO4/T0 on the one hand and 0.6V between GPIO4/T0 and 3.3V. From GPIO4/T0 to 5V gives 2.1V, so there is some more logic involved somewhere behind GPIO4/T0.
  • Pins can be assigned in the header, above ‘void setup()’, using four indicators:
    • Type, for example ‘int’;
    • Name of the variable for the pin, for example ‘touch_pin’
    • Assignment using the equal sign (=);
    • GPIO number, just ‘4’ in this case;
    • Don’t forget the semicolon!
    • The whole assignment looks like: int touch_pin = 4
    • While reading: touchRead (touch_pin)
  • Pins can be read inline without assigning a variable as well: just write the number of the GPIO on the spot where it is needed:
    • touchRead (4)
  • Arduino is not touchy about spaces between brackets and letters. A space “touchRead ( 4 )” gives the same result as no space “touchRead(4)”.

For future reference, the file with the code is attached.

Print this entry

Fritz!Box configuration editing – as text

AVM offers a friendly user interface with Fritz!OS for their Fritz!Box’es to unleash a nice range of features. Many things are possible, though some things take quite a few clicks.

One of the things that take many clicks, is arranging port fortwarding for hosts on the LAN.

The easiest way, after a fashion, is to make a backup of the configuration, make changes and import the file again. The difficulty here is that the file is checksummed, and Fritz refuses to read the configuration.

While the ages, solutions have been written in various languages. I use a python script, fritzchecksum, written by Mementum/DRe.

It is an pip-installable module, pip install fritzchecksum, takes a Fritz-file as input and returns the old and new checksum for easy search and replace. The program supports automatic editing of the file as well, I have always replaced by hand.

For future reference, the zip contains the current download from github. Should not be necessary to download it here, but you never know!

Print this entry