Tracking temperature and humidity in our cellar

So we got to rent a new room in the cellar. It is a bit exposed, and we are not absolutely sure that it is actually frost-free. Or how humid the room is for that matter. How to track that? An arduino with a digital thermometer? With an SD-card reader? Or a Raspberry Pi?

The problem is that the room is too far from our appartment ruling out something connected to the internet – unless I want to go full IoT and set up something with a mobile connection.

After a couple of hours considering this, I came up with this basic plan:

  • Connect a digital thermometer and hygrometer to a Raspberry Pi Zero.
  • Write something that reads the values, and collect the data.
  • Write something else, that tries to connect to a mobile hotspot from my cell-phone.
  • When the connection is made – dump the collected data somewhere.
  • Make sure that you pass the room on a regular basis with the mobile hotspot active.

How to do that? I already had a Raspberry Pi Zero v 1.1 lying around. It has build-in wifi. First step is to set it up with a fresh SD-card:

  1. Download the Raspbian Buster Lite image from https://www.raspberrypi.org/downloads/raspbian/
  2. Inset the sd-card in the computer, and follow the instructions on https://www.raspberrypi.org/documentation/installation/installing-images/README.md. I already had Balena Etcher installed.

Next, it would be nice to connect to it via USB, rather than connecting the Pi to a screen and work directly on it. In order to be able to do that, I go to the boot-folder on the newly flashed SD-card. There I do this:

  1. add the line “dtoverlay=dwc2″ at the very bottom of config.txt
  2. Open the file cmdline.txt, locate the parameter “rootwait” and immediately after that, add this “modules-load=dwc2,g_ether”.
  3. Make af file called “ssh”

Now, in principle, you move the sd-card to your Pi, connect it to the UBS-port on your computer, and you should be able to ssh into pi@raspberrypi.local, using raspberry as the password.

However, it is not quite that simple. When the Pi has been connnected to the laptop, go to settings, choose the wired connection, choose IPV4, and change the “method” to only link-local (do the same for IPV6). And under Identity, change the name to raspberrypi.local.

And now we can ssh into it.

Next step is to get some temperature and humidity readings.

For that purpose, I’m using a DHT22 sensor. More specifically an already wired up sensor. It has four connections, but I’m only using three. The red wire, power is connected to a 3.3V, the black wire to ground, and the yellow data-wire to any GPIO pin. I’m using pin 2

Next – after the Pi is again connected to power, and I have SSH’ed into it, some packages need to be installed.

Before that can be done, I need to get it connected to wifi.

As I am going to use my cell-phone for that I set that up to provide a hotspot. The ssid (or name of the hotspot) is set to NusseMobil, and the password to 3.141592653.

Then I edit the file /etc/wpa_supplicant/wpa_supplicant.conf file on the Pi:

sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

And add this to the end of the file:

network={
ssid=”NusseMobil”
psk=”3.141592653″

Then I run this command:

wpa_cli -i wlan0 reconfigure

to get the Pi to take in the new network configuration.

Testing: Unplug the Pi from the laptop, and connect it to a separate power source. Does the Pi connect to the hotspot? If so, stuff is working, and I plug it into the laptop again.

Now I ssh into the Pi, make sure that there is live connection to the web (ping www.dr.dk is the standard way in Denmark to test that)

Now the necessary packages can be installed:

sudo apt-get update

sudo apt-get install build-essential python-dev python-openssl git

Lets see if it works

cd examples

sudo ./AdafruitDHT.py 22 2

22 because I am working with the DHT22 sensor, 2 because it is connected to GPIO 2 on the board.

Neat. Currently the temperature is 27.2 and the humidity is 55.1%

I have not compared with other thermometers, but it seems plausible.

The sensors in this package is only ready every two seconds. That should be plenty, but I should take that into consideration in the following steps.

I want to save data to a google spreadsheet. In order for that to work, I need an API-key. I follow the instructions on this page:

https://gspread.readthedocs.io/en/latest/oauth2.html

More or less – small changes appears to have crept in. Anyway, I create a new service account caled newcellar, and give it the role of editor.

I get at json file contain interesting and incomprehensible stuff.

I transfer it to the Raspi using ssh:

sudo rsync /path/to/local/file username@PCB:/path/to/remote/destination

Within the file is a mail-adress. I make a new google drive sheet, and share it with that mailadress.

editing the example from the package:

sudo nano google_spreadsheet.py

I add json filename and spreadsheet name

And try to run it:

sudo ./google_spreadsheet.py

Nope! A couple of packages are still missing:

pip install gspread

pip install –upgrade oauth2client

And then I can run it. I get an error telling me that I have forgotten to activate the API. Luckily the error provides the link I need to go to.

And after a couple of minutes the change has propagated through Googles servers, and things are working. The spreadsheet are now steadily being populated with temperature and humidity readings every 30 seconds.

Nice!

How long can I run it on batteries?

That depends on how much power is drawn by the Pi.

This site:

Raspberry Pi Power Consumption Data

has measured the power consumption by a Pi Zero w to about 250 mA. Battery capacity is measured in Ah (amp hours, usually as mAh).

The powerbank I am going to use initially, is 15.000 mAh, giving me 15000/250 60 hours of operation.

Hykleri

Hykleri er at foregive at have en særlig tro, holdning, værdisæt, følelse, kvalitet eller standard, som man ikke har.

Dobbeltmoral: indstilling der fordømmer visse forhold og samtidig accepterer visse andre, lige så forkastelige forhold

Og jeg hader begge dele.

Weird behavior of is.numeric()

An interesting observation. Please note that I have absolutely no idea about why this happens. (at least not at the time of first writing this)

In our datalab, ingeniuously named “Datalab” (the one at KUB-North, because contrary to the labs at the libraries for social sciences, and for the humanities, we are not allowed to have a name), we were visited by at student.

She wanted to make a dose-response plot. Something about the concentration of something, giving some clotting of some blood. Or something…

Anyway, she wanted to do a 4-parameter logistic model. Thats nice, I had never heard about that before, but that is the adventure of running a datalab, and what makes it fun.

Of course there is a package for it, dr4pl. After an introduction to the wonderful world of dplyr, we set out to actually fit the model. This is a minimal working example of what happened:

library(tidyverse)
library(dr4pl)

data <- tibble(dose= 1:10, response = 2:11)

dr4pl(data, dose, response)
## Error in dr4pl.default(dose = dose, response = response, init.parm = init.parm, : Both doses and responses should be numeric.

WTF? “Both doses and responses should be numeric”?. But they are!

is.numeric(data$dose)
## [1] TRUE
is.numeric(data$response)
## [1] TRUE

The error is thrown by these lines in the source:

if(!is.numeric(dose)||!is.numeric(response)) {
    stop("Both doses and responses should be numeric.")
  }

Lets try:

if(!is.numeric(data$dose)||!is.numeric(data$response)) {
    stop("Both doses and responses should be numeric.")
  } else {
    print("Where did the problem go?")
  }
## [1] "Where did the problem go?"

No idea. Did it disappear? No:

dr4pl(data, dose, response)
## Error in dr4pl.default(dose = dose, response = response, init.parm = init.parm, : Both doses and responses should be numeric.

Looking at the data might give us an idea of the source:

str(data)
## Classes 'tbl_df', 'tbl' and 'data.frame':    10 obs. of  2 variables:
##  $ dose    : int  1 2 3 4 5 6 7 8 9 10
##  $ response: int  2 3 4 5 6 7 8 9 10 11

Both dose and response are integers. Might that be the problem?

data <- tibble(dose= (1:10)*1.1, response = (2:11)*1.1)
dr4pl(data, dose, response)
## Error in dr4pl.default(dose = dose, response = response, init.parm = init.parm, : Both doses and responses should be numeric.

Nope. Both dose and response are now definitely numeric:

str(data)
## Classes 'tbl_df', 'tbl' and 'data.frame':    10 obs. of  2 variables:
##  $ dose    : num  1.1 2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 11
##  $ response: num  2.2 3.3 4.4 5.5 6.6 7.7 8.8 9.9 11 12.1

But the problem persists.

Might this be the reason?

head(data,2)
## # A tibble: 2 x 2
##    dose response
##   <dbl>    <dbl>
## 1   1.1      2.2
## 2   2.2      3.3

It is a tibble. And the variables are reported to be doubles.

But according to the documentation:

“numeric is identical to double (and real)”

That should not be a problem then.

However. In desperation, I tried this:

c <- data %>% 
  as.data.frame() %>% 
  dr4pl(dose, response)

And it works!

Why? Absolutely no idea!

Or do i?

The problem is that subsetting a tibble returns a new tibble. Well, subsetting a dataframe returns a dataframe as well?

It does. Unless you subset out a single variable or observation.

In a dataframe, df$var returns a vektor, containing the values of var in df.

If, however, df is a tibble, df$var will return a tibble, with just one variable.

Hvor mange brune mennesker er der i Danmark?

Eller, er det urimeligt at der kun er en brun minister i den nye regering?

Jeg er faktisk ikke meget for at opdele folk efter hudfarve. Den bør være ret ligegyldig. Med mindre den er grøn eller blå. Eller postkasserød. I så fald vil jeg nok ringe til Niels Bohr Institutet, og spørge om de har et direkte nummer til en relevant international organisation, der håndterer gæster fra andre planeter.

Anyway. Jeg så nogen beklage sig over at der kun er 1 “brun” minister blandt de 20. Altså 5% “brune”.

Er det urimeligt? Det er lidt svært at svare på. Det er en socialdemokratisk regering. Dens ministre rekrutteres derfor overvejende fra den socialdemokratiske folketingsgruppe, som er på 46 medlemmer. Tre af dem er “brune”. For en passende værdi af brun. Ministeren, Mattias Tesfaye, er søn af en etiopisk far, og en etnisk dansk mor. Og han er åbenbart brun nok til at blive betegnet som brun (det giver mig nogle ubehagelige associationer til amerikansk sydstats-raceretorik, hvor blot en enkelt dråbe negerblod var nok til at du var et undermenneske. Eller noget). Men fair nok, han er mere brun end jeg er. På den anden side veksler jeg også mellem kridhvid og solskoldet, afhængig af årstiden, så det siger ikke ret meget.

Men hvis fordelingen af brune ministre skal afspejle fordelingen af brune socialdemokratiske folketingsmedlemmer, så burde 6,5% af ministrene være brune. Når 5% af dem er, må man sige at være ret tæt på det forventede.

Hvordan med hele folketinget?

Socialdemokratiet har som nævnt 3.

Venstre har 0, Dansk Folkeparti 0, Radikale Venstre 1, SF 1, Enhedslisten 0. Eller måske 1. Det kommer an på hvor rent hvidt blod man mener Victoria Velasquez har. Hun ser ret hvid ud, men hvad ved jeg. Konservative har 1, Alternativet 1, Nye Borgerlige 0, Liberal Alliance 0. De nordatlantiske mandater ved jeg ikke hvordan man skal gøre op. Men lad os bare sige at de grønlandske MF’ere er “brune”, og de færøske hvide.

Det giver ialt 10. Hvor vi altså går ud fra, at det spansk lydende navn er brunt nok, og at grønlændere også kan regnes som brune.

Så 5,6% af folketinget er brune. Højt sat.

At 5% af ministerlisten er “brune” er vist ikke udtryk for en kritisabel underrepræsentation.

Men afspejler folketingets sammensætning, eller den socialdemokratiske folketingsgruppe, befolkningen? Det er også lidt vanskeligt.

Danmarks Statistik har fine opgørelser. Bare ikke på hudfarve. Det er ikke så meget dem der har dansk oprindelse, der er interessante. Det er indvandrere og efterkommere. Man kan kigge på alle landene. Men det er ikke helt lige til. Indvandrere fra USA, kan sagtens være meget brune. Så kan man dele op på vestlige og ikke-vestlige lande. Er folk fra hviderusland brune? Hvad med Argentina? Eller Israel? De er alle ikke-vestlige. Anyway. Lad os beslutte os for at alle indvandrere og efterkommere fra ikke-vestlige lande er at regne som brune. Jeg er for doven til at trække tal for alle lande, og de bliver alligevel ikke tilstrækkeligt præcise.

Hele den danske befolkning er på 5,8 millioner. Og indvandrere og efterkommere fra ikke-vestlige lande, udgør 8,7% heraf. Det er ikke den helt rigtige fordeling. Børn under 18 er ikke valgbare!

Den del af befolkningen der er over 19 – ja, det burde være 18, men som nævnt er jeg doven og gad ikke trække så detaljerede tal ud – er i alt på 4,5 millioner. Og 8,3% er fra ikke vestlige lande.

Så hvis indvandrere og efterkommere fra ikke-vestlige lande skulle være helt fair repræsenteret på ministerlisten, skulle der altså være 8,3%. Jeg ved ikke helt om det er rimeligt at brokke sig over at andelen “kun” er 5%. Havde der været 2 brune ministre, havde de været overrepræsenteret. Tallet bliver i øvrigt mindre hvis vi kigger på hvem der har dansk statsborgerskab, og dermed er valgbare.

Med andre ord, der er et ret repræsentativt antal brune mennesker på ministerlisten – der er næppe noget reelt at brokke sig over i den sammenhæng (men rigeligt andet…)

Og så efterlades jeg igen med en let kvalme over symmetrien i anti-racisterne og racisternes virkelighedsbillede. Nej, der er ikke supermange brune mennesker i Danmark. Danmark er et bemærkelsesværdigt hvidt land. Antiracisterne er utilfredse fordi de åbenbart lever i en alternativ virkelighed hvor der er utroligt mange brune mennesker i Danmark, og hvis der kun er en enkelt brun person blandt 20 mere eller mindre tilfældigt udvalgte personer, så er det udtryk for undertrykkende racisme. Racisterne lever åbenbart i den samme alternative virkelighed, hvor landet næsten er overtaget af brune mennesker – hvorfor de allesammen skal smides ud.

Og så tror jeg det er tid til at jeg går i bad. Den der opdeling af mennesker efter hudfarve får mig til at føle mig beskidt.