2020-01-15

How To Create Temperature Monitor with Email Alerts

I need to monitor the temperature in a room and make sure it doesn't get too cold in the winter, so I decided to setup a raspberry pi as my temperature sensor, and create a simple application/service that regularly checks the temperature and updates me via email.

Once you know what you're doing it's really quite easy.  I had to do a lot of research, so it took me longer than I'd like to admit, but it was fun setting everything up and learning.  I stuck with python throughout because it simplifies everything.

Reading the Temperature 

First, you need a temperature sensor.  There's a really good tutorial by circuitbasics.com.  All you need is a raspberry pi 3b (older and cheaper ones probably work too), DS18B20, and a 4.7K resistor (anything between 1K and 10K would probably work).  I also used a 2x4 .1" female header for soldering the temperature sensor circuit so that I can easily connect it to the raspberry pi.

After connecting the temperature sensor circuit to the raspberry pi as shown in the tutorial and enabling the 1-wire interface, you'll be able to read the temperature sensor.

  1. Add this to the end of /boot/config.txt: dtoverlay=w1-gpio
  2. Reboot the raspberry pi
  3. Execute: sudo modprobe w1-gpio;sudo modprobe w1-therm
  4. Execute: cat /sys/bus/w1/devices/28-*/w1_slave
  5. The temperature is at the end (t=x) in thousandths of degrees Celsius
The tutorial also includes a bit of python code to read and output the temperature.

Web Service

The web service was extremely simple to create.  I used flask, and followed the hello world tutorial from pythonspot.com.  Then I added the ip address for external access, customized the port number and merged the temperature reading python code from before.  The web service I created simply returns the temperature in degrees Celsius because I wasn't interested in any other information.

Raspberry Pi Startup

Next, I wanted the python based web service to run on startup so that it'll always be available.  Following the example by instructables, I configured cron to start the service on boot.  To verify, I restarted the raspberry pi, went to the URL in my browser and made sure the temperature showed up.

Independent Polling Temperature Service

My last step was to setup a separate service on another computer that polls the temperature, verifies it, and notifies on error.  I'm using a different computer because I want to get a notification if the room gets cold (below zero), and the chips on the raspberry pi are only commercial grade (0 to 70C).  It would probably still work until -10C, but I still decided to keep it separate.
So I wrote a python service that reads the temperature, compares it to thresholds and sends an email if it's too cold.  I check the temperature hourly, but that's easily changed, I also have a very high temperature threshold because the temperature sensor reads hot (it's kept warmer than ambient by the raspberry pi) and I track the temperatures and email trends daily.  If reading the temperature ever fails I also send an email, which I found to have a lot of false positives so I added a couple of retries when reading the temperature.  I also write messages to syslog (I'm polling from a Linux box) so that I can easily see recent temperature readings.
I did fool around with setting up my polling application as a service that would automatically restart, but didn't fully get that working.

Anyway, here's my temperature poller.  It has been running for a couple of weeks without a glitch.

Source Email Address

One last note, I created a separate email address to send the notification emails from because I had to reduce the security on it.  I don't use the email address for anything except sending these emails so if it does get hacked it's not a big deal.

Let me know if you're interested in other source and I'll post that too.

2019-01-13

Accidentally Sending Emails to the Wrong Person?

Everyone has sent a message to the wrong person at least once.  Maybe it's an text message and you accidentally respond to the wrong conversation, or added the wrong name to an email.  Quite often it isn't a huge deal because of the fact we've all done it.  You'll receive a message that makes absolutely no sense, maybe responding with a "?", or you get a follow up soon after telling you to please ignore it.

Sending increasing personal information is embarrassing, and in business sending private or confidential information can be a huge problem.

In Outlook, it's quite easy to add a macro that double checks the recipients before an email is sent, comparing the domain name (ex. gmail.com, companyy.com, etc.).  Typically when I send emails to multiple recipients they have the same domain name, ignoring the domain of the company I work for.  

So here's what I use to make sure I don't accidentally CC the wrong person.  I added the VBA code at the bottom of the post to Outlook, and I get a verification popup every time I send an email to multiple domains that aren't in my ignoreDomains and ignoreStartsWith lists.

Another thing that can be done, which I do as well because quite often I think of extra things to add to an email right after sending it, is to add a rule to delay sends by X minutes.

Useful Links:



Option Explicit

Private Function ignoreDomains() As Variant
    ignoreDomains = Array("example.com", "example2.com")
End Function

Private Function ignoreStartsWith() As Variant
    ignoreStartsWith = Array("jay@trustworthy.com", "bob@trust.com")
End Function

Private Sub Application_ItemSend(ByVal objItem As Object, cancel As Boolean)
    Dim email As mailItem
    Dim warn As Boolean
    Dim message As String

    If ("MailItem" = TypeName(objItem)) Then
        Set email = objItem
        warn = domainMismatch(email, message)
        cancel = verifyCancelSend(warn, "This email is addressed to multiple domains." & vbCrLf & vbCrLf & message)
    End If
End Sub

Private Function verifyCancelSend(ByRef warn As Boolean, msg As String) As Boolean
    Dim retVal As Boolean
   
    If (warn) Then
        Beep
        retVal = (MsgBox(msg & vbCrLf & vbCrLf & "Would you like to cancel sending the email?", vbYesNo, "Cancel Send Confirmation") <> vbNo)
    End If
   
    verifyCancelSend = retVal
End Function

Private Function domainMismatch(mi As mailItem, message As String) As Boolean
    Dim retVal As Boolean
    Dim rc As Recipient
    Dim domain As String
    Dim baseDomain As String
    Dim ignoreStartValue As Variant
    Dim ignoreDomainValue As Variant
    Dim ignoreStart As Boolean
    Dim ignoreDomain As Boolean
   
    message = ""
    baseDomain = ""
    retVal = False

    For Each rc In mi.Recipients
        ignoreStart = False
        For Each ignoreStartValue In ignoreStartsWith()
            If (LCase(ignoreStartValue) = LCase(Left(rc.Address, Len(ignoreStartValue)))) Then
                ignoreStart = True
            End If
        Next
       
        If (Not ignoreStart) Then
            ignoreDomain = False
           
            domain = LCase(Right(rc.Address, Len(rc.Address) - InStr(rc.Address, "@")))
           
            For Each ignoreDomainValue In ignoreDomains()
                If (ignoreDomainValue = domain) Then
                    ignoreDomain = True
                End If
            Next
           
            If (Not ignoreDomain) Then
                If "" = baseDomain Then
                    message = rc.Address
                    baseDomain = domain
                End If
               
                If (baseDomain <> domain) Then
                    retVal = True
                    message = message & vbCrLf & rc.Address
                End If
            End If
        End If
    Next

    domainMismatch = retVal
End Function

2018-04-09

How to Setup Outline VPN at Home and Save the Cloud Hosting Costs

A while ago I had OpenVPN setup, but it was quite a bit of work.  Then I upgraded something and it broke, and I never got around to fixing it.  So setting up VPN access to my home network has been on my to do list for a while.  Then I noticed the release of Jigsaw's (Alphabet/Google) Outline VPN, and figured I'd give it a try.

Setting up Outline VPN took a lot longer than it should have because I didn't find a really good resource for installing it at home.  Everything I found left out some of the key details I was interested in.  Specifically, I wanted to know a bit about what's going on, and wanted to minimize the number of ports I have open and/or forwarded on my home router.  

First, I have Ubuntu 16.04, so the steps will be best described for that OS.  However, it shouldn't be that difficult to translate them to a different OS.
  1. Verify you have an externally accessible IP address.  
    1. Log into the router or cable modem your ISP provided
    2. Check the setup or status page
    3. There will be a WAN IP address.  If it's not within one of the following sets, private IP addresses, then you're good to go (10.0.0.0 - 10.255.255.255, 172.16.0.0 - 172.31.255.255, 192.168.0.0 - 192.168.255.255)
  2. Install Docker - Follow the link for the complete steps, or try the following:
    1. curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    2. sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    3. sudo apt-get update
    4. sudo apt-get install -y docker-ce
  3. The following steps generally following Outline VPN standard installation steps
  4. Download the install script and save it locally
    1. sudo wget https://raw.githubusercontent.com/Jigsaw-Code/outline-server/master/src/server_manager/install_scripts/install_server.sh > install_server.sh
  5. Set the port used by Outline Manager, by editing install_server.sh.  Then either update get_random_port to return a number between 1024 and 65535, or update the script at around line 99 to use the specific port number instead of calling get_random_port (which returns a random port)
    1. ex. Replace 'echo $num;' with 'echo 65333;'
  6. Update your router and/or firewall to forward the specific port to the computer that you're installing Outline on.
  7. Install Outline VPN, execute (-x is optional, and is for debugging purposes).  Take note of the apiUrl and certSha256 output at the end of the command assuming it's successful.
    1. cat install_server.sh | sudo bash -x
  8. Assuming the manager port is not blocked, the install will complete.
  9. Download Outline Manager from the following site
    1. https://getoutline.org/en/home
  10. Run Outline Manager and select the bottom option
  11. Enter the apiUrl and certSha256 from step 7 in the Outline Manager and click OK
  12. So that you can track usage, in the connected Outline Manager, add a key and give it a useful name.
  13. Click SHARE and copy the generated URL using the device you want to connect to your VPN
  14. The URL will look something like the following.  Again go to your firewall and/or router and forward the <PORT NUMBER> to the computer that you're installing Outline on.
    1. https://s3.amazonaws.com/outline-vpn/index.html#/invite/ss%3A%2F%2abcdefg...%3D%40<IP ADDRESS>%3A<PORT NUMBER>%2F%3Foutline%3D1
  15. Go to the URL from step 13.  You will be directed to install the Outline application, and add the server.
  16. You're done.  To test, click CONNECT and try to access something from your home network.

I use mine for my nightly backups of pictures and videos I've taken on my phone to my NextCloud installation that I don't want publicly accessible.


If you run into problems during the install, stopping and removing all the related docker images will be useful:

  • sudo docker stop shadowbox;sudo docker rm shadowbox;sudo docker stop watchtower;sudo docker rm watchtower


Useful links: