Category Archives: Telldus

Checking who is home with PowerShell

The first thing that comes to mind when doing home automation is probably controlling lights and sockets depending on if someone is home or not. Most apps I’ve seen for this can’t handle multiple family members though, which is quite useless. You don’t want to turn on all the lights when you come home if someone else is sleeping or watching a movie with dimmed lights for example.

So how to figure out who is currently at home?

The method I chose was to check if our phones are connected to WiFi. There are a few obstacles to overcome before this works though, for example:

  • Many smartphones turn off WiFi to save battery (for example the iPhone)
  • They use dynamic IP-addresses and name resolution is not always available, so how to find them?
  • The script therefor checks for how long a phone has been offline before it does any changes, and it starts off by doing a pingsweep to populate the arp-table to find the different phones MAC-addresses.

    This scripts updates the status of each phone in a file on disk and also changes a device in Telldus Live! to On/Off. That makes it possible to filter events in Telldus Live! based on who’s home, or when the last person leaves.

    The script-module used here can be found in this post.

    The script looks like this:

    # Import the telldus module
    Import-Module 'C:\TelldusScripts\Telldusv2.psm1'
    
    # Set telldus credentials
    $Username = "[email protected]"
    
    # Get the password from the file (a saved PowerShell credential)
    $Password = Get-Content 'C:\TelldusScripts\TelldusPassword.txt' | ConvertTo-SecureString
     
    # Build the credential
    $TelldusCredential = New-Object System.Management.Automation.PsCredential($Username,$Password)
    
    # Specify path to the "FamilyMember" file
    $FamilyMemberFile = "C:\TelldusScripts\FamilyMembers.csv"
    
    # How many times should we wait for the network scan to finish?
    $MaxWaitRounds = 10
    
    # How long should we sleep between each "network scan check"?
    $WaitBetweenNetworkScanSeconds = 10
    
    # Load that file into an array
    $FamilyMembers = Import-Csv $FamilyMemberFile -Encoding utf8
    
    # Get the subnets
    $DeviceSubnets = $FamilyMembers | select -ExpandProperty WiFiSubnet | Sort-Object -Unique
    
    # Set the time limit for when a device should be considered offline
    $NotHomeTimeLimit = 120
    
    # Do a ping sweep in those subnets to find any device MACs
    foreach ($DeviceSubnet in $DeviceSubnets) {
    
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 1..25 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 26..50 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 51..75 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 76..100 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 101..125 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 126..150 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 151..175 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 176..200 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 201..225 | % { ping "$Subnet$_" -n 1 -w 1 } }
        Start-Job -ArgumentList $DeviceSubnet -ScriptBlock { $Subnet=$args[0] ; 225..255 | % { ping "$Subnet$_" -n 1 -w 1 } }
    }
    
    $NumberOfRounds = 1
    
    while ((Get-Job -State Running).count -gt 0 -AND $NumberOfRounds -le $MaxWaitRounds) {
        Write-Output "Scanning network for devices... (Round: $NumberOfRounds of max $MaxWaitRounds. Number of jobs running: $((Get-Job -State Running).count).)"
        sleep -Seconds $WaitBetweenNetworkScanSeconds
        $NumberOfRounds++
    }
    
    
    # Loop through the family members
    foreach ($FamilyMember in $FamilyMembers) {
    
        # Reset the variables
        $FamilyMemberLastStatus = $null
        $FamilyMemberCurrentStatus = $null
    
        # Get last status
        $FamilyMemberLastStatus = Get-Content $($FamilyMember.StatusFile)
        
        # Get current status by name
        $FamilyMemberCurrentStatus = Test-Connection $($FamilyMember.DeviceName) -Count 1 -Quiet
    
        # Get it by MAC if that failed
        if ($FamilyMemberCurrentStatus -eq $false) {
            $CurrentFamilyMemberIP = $null
            $CurrentFamilyMemberIP = arp -a | select-string $FamilyMember.DeviceMAC | % { $_.ToString().Trim().Split(" ")[0] } | select -First 1
    
            $FamilyMemberCurrentStatus = Test-Connection $CurrentFamilyMemberIP -Count 1 -Quiet
        }
        # Check if the current status is online
        if ($FamilyMemberCurrentStatus -eq $true) {
            
            Write-Output "$($FamilyMember.Name)'s device is online!"
    
            # Update status file
            Write-Output $true | Out-File $FamilyMember.StatusFile
    
            # If it was offline last time, set the telldus device to on
            if ($FamilyMemberLastStatus -ne $true) {
                Write-Host "This is a change since last run, setting device to on."
                Connect-TelldusLive -Credential $TelldusCredential
                Set-TDDevice -DeviceID $FamilyMember.DeviceID -Action turnOn
            }
        }
        # So the device was offline...
        else {
            Write-Output "$($FamilyMember.Name)'s device is offline!"
    
            # Verify if this is temporary (iPhone sleep mode) or if it has been offline for a while
            $LastChangeTime=(gci $($FamilyMember.StatusFile)).LastWriteTime
            $Now=Get-Date
            $LastChangeTimeSpan = (New-TimeSpan -Start $LastChangeTime -End $Now).TotalMinutes
    
            # Only change status if the device has been offline for $NotHomeTimeLimit minutes.
            if ($LastChangeTimeSpan -gt $NotHomeTimeLimit -AND $FamilyMemberLastStatus -eq $true) {
                # It was, update statusfile to offline
                Write-Output $false | Out-File $($FamilyMember.StatusFile)
    
                Write-Output "This device has been offline for more than $NotHomeTimeLimit minutes. Turning Telldus device off..."
                Connect-TelldusLive -Credential $TelldusCredential
                Set-TDDevice -DeviceID $FamilyMember.DeviceID -Action turnOff
            }
        }
    }
    

    I’ve scheduled it to run quite often to always check if someone has arrived. Hopefully the comments in code will give you the help you need, if not, post a comment below and I’ll be glad to help you!

    The csv file ($FamilyMemberFile, C:\TelldusScripts\FamilyMembers.csv) used in the script above should have the columns Name, DeviceName, DeviceMAC, WiFiSubnet, StatusFile, DeviceID.

    Name = The name of the person who owns the device
    DeviceName = The DNS name of the device. iPhones use “DeviceName.local”
    DeviceMAC = MAC-address of the devices, use “-” as a separator.
    WiFiSubnet = The subnet where the phone gets its IP-address.
    StatusFile = The path to a file unique for this phone where the status can be written (if it’s home or not)
    DeviceID = The device id in Telldus Live! that is used to filter if this person is home.

    Example:
    Name,DeviceName,DeviceMAC,WiFiSubnet,StatusFile,DeviceID
    John,”JohnsiPhone.local”,”00-01-03-04-05-06″,”192.168.1.”,”C:\TelldusScripts\IsJohnHome.txt”,”123456″

    The script will loop through all devices added and set the status in the status file (True/False) aswell as the device in Telldus Live! (On/Off) depending on if the phone was online or not.

    Hope that made sense for you!

    Home Automation Module Updated

    The home automation module for the Tellstick Net is now updated.

    The main difference is that some executing cmdlets dont generate output if you dont use “-Verbose” and that authentication is set up by the “Connect-TelldusLive”-cmdlet (Which uses a PSCredential). That means that the Username and Password parameters are removed from all other cmdlets. This makes the usage a lot simpler and also a lot quicker.

    A screenshot to get you an idea on how to use it: (Device names are in Swedish, sorry…)
    telldusmodule

    The code is available here. (Updated at 2016-08-23)

    Wake me up, when traffic calms down… (Home Automation)

    Why do home automation with PowerShell?

    There are certainly other solutions out there which are great, even excellent. For me personally, it’s mainly because it’s fun to be able to build parts of it by yourself, you learn a lot by doing it, but you can also base your tasks on almost any piece of information out there.

    I’ll give you an example!

    I’ve started to go to work after the traffic calms down in the morning, I have a pretty good idea of when this usually happens, but sometimes there is no traffic jams at all, and sometimes it’s completely hopeless.

    Wouldn’t it be nice to be able to utilize live traffic information on the internet, and based on that trigger your wake up call? At least I thought so 🙂

    First of all, try to find a provider for traffic information near you, and make sure you don’t break their ToS by fetching that information in a automatic way (ie. web scraping).

    I won’t go into detail on how to build a webscrape-cmdlet right now, but I’ll show you how to use it when it’s done. (A guide to web scraping available here, here and here.)

    This is the script I run every morning, I think the code comments will be enough to explain how it works:

    # Import the Telldus module
    Import-Module '.\Telldus.psm1'
    
    # Import the Module containing your traffic parser
    Import-Module '.\WebDataModule.psm1'
    
    # Set your home and work address
    $HomeAddress="Homeroad 1, MyTown"
    $WorkAddress="Workaround 1, WorkTown"
    
    # Set a max traveltime limit (in this case, in minutes)
    [int] $TravelTimeLimit = 30
    
    # I want it to be under this value for $NumberOfTimes consecutive times
    [int] $NumberOfTimes = 3
    
    # Make sure it does'nt get $True on first run
    [int] $CurrentTravelTime = $TravelTimeLimit+1
    
    # Reset variable to zero
    [int] $NumberOfTimesVerifiedOK = 0
    
    # Run until the traveltime limit has been passed enough times
    while ($NumberOfTimesVerifiedOK -lt $NumberOfTimes) {
        
        # Reset variable
        $CurrentTravelTime = $null
    
        # Load new data, the "Get-Traffic"-cmdlet is my traffic parser
        [int] $CurrentTravelTime = Get-Traffic -FromAddress $HomeAddress -ToAddress $WorkAddress | select -ExpandProperty TravelTime
    
        # Check if it is below your traveltime limit, and that it is not $null (cmdlet failed)
        # Increase $NumberOfTimesVerifiedOK if it was ok, or reset to zero if it wasn't
        if ($CurrentTravelTime -ne $null -AND $CurrentTravelTime -lt $TravelTimeLimit) {
            $NumberOfTimesVerifiedOK++
        }
        else {
            $NumberOfTimesVerifiedOK = 0
        }
    
        # Write current status
        Write-Output "Traffic has been verified as OK $NumberOfTimesVerifiedOK consecutive times"
    
        # Pause for a while before checking again, 10 minutes or so...
        Start-Sleep -Seconds 600
    }
    
    # The while loop will exit when traveltime has been verified enough times.
    
    # Write status
    Write-Output "Initiating sunrise, current travel time to $WorkAddress is $CurrentTravelTime minutes, and has been below $TravelTimeLimit for $NumberOfTimes consecutive times."
    
    # Time to initiate the "sunrise effect"
    
    # Set the device id for the lamp you want to light up
    $BedroomLampDeviceID="123456"
    
    # Set start dimlevel
    $SunriseDimlevel = 1
    
    # Set how much it should increase everytime we "raise" it
    $SunriseSteps = 5
    
    # Set your Telldus credentials
    $Username="[email protected]"
    $Password="MySecretPassword"
    
    # Kick off the "sunrise-loop"
    while ($SunriseDimlevel -lt 255) {
        # Write some status
        Write-Output "Setting dimlevel to $SunriseDimlevel"
    
        # Set the new dimlevel
        Set-TDDimmer -Username $Username -Password $Password -DeviceID $BedroomLampDeviceID -Level $SunriseDimlevel
    
        # Sleep for a while (30 seconds makes the "sunrise" ~30 minutes long depending on your $SunriseSteps value)
        Start-Sleep -Seconds 30
    
        # Set the next dimlevel
        $SunriseDimlevel=$SunriseDimlevel+$SunriseSteps
    }
    
    # Set the lamp to full power (loop has exited) and exit
    Set-TDDimmer -Username $Username -Password $Password -DeviceID $BedroomLampDeviceID -Level 255
    Write-Output "Maximum level is set."
    
    

    This script is scheduled to run in the morning (on week days) around the earliest time I want to go up, the first loop will run until traffic calms down, and then start the “sunrise”-loop which will run until the light reaches its maximum level (255).

    You could of course turn on other stuff as well, like a coffee brewer (make sure you don’t do this while you are away…), a radio, play some music or something else.

    That is one of the (many!) pro’s of doing things with PowerShell! 🙂

    Watering plants with PowerShell

    Since we moved to an apartment with a balcony we wanted to have some plants there. The problem is that we’re a lot better at killing plants than actually taking care of them. And even the few days when we actually did remember to water them, the plants could dry out on hot days.

    So, how to solve this? With PowerShell of course! 🙂

    You could start of with the Telldus PowerShell Module from this blogpost (though, this one is preferred since it handles credentials a lot better). The module is under development but works for checking temperatures, dimming or turning on/off devices etc.

    You also need something to water with, I went with a pump from Gardena which runs for 1 minute when turning it on, or 1 min/24h if turned on constantly. This means that switching it off/on will start a watering session. The waterflow is controlled by using different outlets from the pump.

    After adding the devices to Telldus Live! you can just open up your favorite powershell editor, import the module and start coding. (The module requires at least PowerShell v3)

    An example of how it can be done follows. (The below module has been updated, make sure you check out the new version that uses a PSCredential among other things!)

    First import the module, set the credentials and some variables needed: (passthrough for credentials (using “secure string”) is on the ToDo-list)

    Import-Module C:\Scripts\Telldus\Module\TelldusModule.psm1
    
    $Username="[email protected]"
    $Password="MySecretPassword"
    
    # At what temperature (and above) should I start the pump?
    $WhenToWaterTemp=25
    
    # If the humidity get's below this value, I will also start the pump
    $WhenToWaterHumidity=40
    
    # How old could the sensor data be before I'll consider it invalid? (in hours)
    $DataAgeLimitInHours=2
    
    # Time zone difference compared to telldus servers.
    $TimeZoneDifference=2
    

    You don’t need to check for how old the sensor data is, but these sensors can sometimes stop updating, and if they do when it’s hot outside, you might end up drowning your plants if you schedule the script to run often.

    We continue to load the data from the sensors:

    You could do it like this:

    # Get the balcony sensor ID
    $BalconySensor=Get-TDSensor -Username $Username -Password $Password | Where-Object { $_.Name -eq "Balcony" }
    
    # Get the sensor data from that ID
    $BalconySensorData=Get-TDSensorData -Username $Username -Password $Password -DeviceID $BalconySensor.DeviceID
    

    Or with a one-liner, like this:

    $BalconySensorData=Get-TDSensor -Username $Username -Password $Password | where Name -eq "Balcony" | Get-TDSensorData -Username $Username -Password $Password
    

    We now know the temperature and humidity (depening on your sensor capabilites) on the balcony, or wherever you have your plants. We continue with the logic for watering:

    # Calculate when to consider the sensor data too old
    $CurrentAgeLimit=(Get-Date).AddHours(-($TimeZoneDifference+$DataAgeLimitInHours))
    
    # Check if the data is too old
    if ($BalconySensorData.LastUpdate -gt $CurrentAgeLimit) {
        # Check if it's too hot or too dry
        if ($BalconySensorData.Temperature -ge $WhenToWaterTemp -or $BalconySensorData.Humidity -le $WhenToWaterHumidity) {
            # If it was, let's give them some water by turning the pump off and then back on
            Write-Output "The plants are sweating (dry and/or hot)! I'm going to give them some water..."
            Get-TDDevice -Username $Username -Password $Password | Where-Object { $_.Name -like "Balcony Watering System*" } | Set-TDDevice -Username $Username -Password $Password -Action turnOff
            Get-TDDevice -Username $Username -Password $Password | Where-Object { $_.Name -like "Balcony Watering System*" } | Set-TDDevice -Username $Username -Password $Password -Action turnOn
        }
    }
    else {
        # The data was too old
        Write-Output "Sensordata is too old!"
    }
    

    That’s basically it! I added some functionality for doing push-notifications to my phone (Growl API and Boxcar works great for this). Or you could just send an e-mail (you probably want to know if the sensor data isn’t getting updated, for example).

    Hope this gives you an idea on what you can do with PowerShell and home automation.

    I will try to add other things that I’ve automated with this module when I get the time!

    If you have any suggestions, please leave a comment below!

    Home Automation With PowerShell

    Home Automation is probably not something we can’t live without. But it is fun 🙂

    A while ago I bought a little device called “Tellstick Net“, which is a device made for controlling other electrical devices, like dimming your lamps, turning on/off sockets, or for receiving data from different sensors, like temperature.

    It had one obvious disadvantage though, it didn’t have PowerShell support…

    Luckily this is a problem that has an easy fix! I went with a “quick and dirty” method of talking to the API site, but it has worked pretty much flawlessly for over a year now.

    I will post more information about this project on this blog, but I thought I could start with some screenshots to help you get an idea on what you can do: (sorry for naming my devices in swedish…)

    telldus cmdlet

     

    telldus_cmdlets2

     

    This module has for example been used for water plants during vacations (giving extra water during hot days), turning of lights when launching media players etc…

    Some usage examples including guides should be coming when I get the time, if you can’t wait, the module is available here.

    New version available here at PoshCode.org. Blog post available here.