AutomatiserarSE.psm1

#
# Module 'AutomatiserarSE'
#
# Created by: Ispep
#
# Generated on: 2016-06-05
#
# Blog www.automatiserar.se
#


function Get-MjVeraMode {
<#
.Synopsis
   Read current mode from Vera Controller with UI7, returns an object current mode.
.DESCRIPTION
   This will allow you to verify what mode your Vera currently running in.
   Created by Ispep
   Added 2016-06-06
   WWW.Automatiserar.se
.EXAMPLE
Get-MjVeraMode -VeraIP Vera
 
Value Mode
----- ----
1 Home
 
.EXAMPLE
Get-MjVeraMode -VeraIP Vera -RequireLogin -VeraCredential (Get-Credential)
 
Value Mode
----- ----
1 Home
 
.NOTES
   This component requires you to have a Vera controller.
#>


    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
    
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
    
        [System.Management.Automation.PSCredential]$VeraCredential
    )

    if (!(Test-Connection $VeraIP -Count 1)){Write-Warning "Unable to connect to IP / name: $VeraIP!, will not continue"; break}

    # Gather information about what mode Vera currently running in.

    if ($RequireLogin)
    {
        # Beginning to check what mode the controller is in, this function will use username and password.
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data with this username: $($VeraCredential.UserName)"
        $VeraMode = Invoke-WebRequest -Uri "http://$($VeraIP):3480/data_request?id=variableget&Variable=Mode" -Credential $VeraCredential
    } 
    
    else 
    
    {
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data Requesting data without username"
       $VeraMode = Invoke-WebRequest -Uri "http://$($VeraIP):3480/data_request?id=variableget&Variable=Mode"
    }


    if ($VeraMode.StatusCode -eq 200)
    {
        # If the HTTP code returns 200 the command was successful
        Write-Verbose "$($MyInvocation.InvocationName):: HTTP code returned was 200, the command was successful"

        $tmpModeValue = switch (($Veramode.Content.trim()))
                       {
                            '1'     {"Home"    ; break}
                            '2'     {"Away"    ; break}
                            '3'     {"Night"   ; break}
                            '4'     {"Vacation"; break}
                            Default {"ERROR"          }
                       }
    
    $VeraModeResult = New-Object -TypeName psobject 
    $VeraModeResult | Add-Member -MemberType NoteProperty -Name "Value" -Value ($Veramode.Content.trim())
    $VeraModeResult | Add-Member -MemberType NoteProperty -Name "Mode"  -Value $tmpModeValue
    
    return $VeraModeResult
        
    }
    
    else 
    
    {
        Write-Verbose "$($MyInvocation.InvocationName):: This command returned other other code than 200, this can indicate that the Vera controller has a new URL"
        Write-Warning "Did not get the response code 200, got this code: $($VeraMode.StatusCode)"
    }

}


function Send-MJSpeak {
<#
.Synopsis
   Send voice message to speaker.
.DESCRIPTION
   This will make your computer read information and tell it with your speakers.
   Created by Ispep
   WWW.Automatiserar.se
.EXAMPLE
   Send-MJ-Speak -message "Hello, its 4 degree Celsius outside today"
.EXAMPLE
   Send-MJ-Speak -message "Hello, its 4 degree Celsius outside today" -
.OUTPUTS
   Bool value are returned.
.NOTES
   This component can be used to read information from systems.
#>

    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    [OutputType([bool])]
    Param
    (
        # This contains the message that you want to read.
        [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]
        $Message,

        # Specify The volume you want to use
        [AllowNull()]
        [ValidateRange(0,100)]
        [int]
        $Volume = 100 # Default volume unless other value is provided

    )

    Begin
    {
        
        
    }
    Process
    {
        $speakMessage = Add-Type -AssemblyName System.speech
        $speakMessage = New-Object System.Speech.Synthesis.SpeechSynthesizer
        $speakMessage.Volume = $Volume
        $speakMessage.Speak($message)
        if ($?){
            return $true
        } else {
            return $false
        }
    }
    End
    {
    }
}


function Read-MJImageRGBPixel {
<#
.Synopsis
 
   Read colour information from defined areas in images, returns RGB info about the area
.DESCRIPTION
   Read colour information from defined areas in images, returns RGB info about the area
   Provide a file path to an image and �X� and �Y� location In the image, this will return an RGB colour code from that area. It�s possible to provide a pixel area to.
   Default an average info from pixels will be 5 pixels +- the selected pixel.
   Created by: Ispep
   Date: 2016-04-20
   Blog: www.Automatiserar.se
.EXAMPLE
   This will find the RGB colour in location X22 and Y33
   Read-MJImageRGBPixel -FilePath "C:\temp\DemoBild2.jpeg" -PixelX 22 -pixelY 43
 
    FilePath : C:\temp\DemoBild2.jpeg
    PixelX : 22
    PixelY : 43
    PixelArea : 5
    Success : True
    ImageWith : 3200
    ImageHeight : 1080
    Red : 247
    Red_Max : 254
    Red_Avg : 234
    Red_Min : 188
    Green : 250
    Green_Max : 254
    Green_Avg : 240
    Green_Min : 188
    Blue : 252
    Blue_Max : 253
    Blue_Avg : 246
    Blue_Min : 188
    ScriptVersion : 1
 
.EXAMPLE
   Read-MJImageRGBPixel -FilePath C:\Temp\DemoBild2.jpg -PixelX 22 -pixelY 43 -PixelArea 2
     
    FilePath : C:\Temp\DemoBild2.jpeg
    PixelX : 22
    PixelY : 43
    PixelArea : 2
    Success : True
    ImageWith : 3200
    ImageHeight : 1080
    Red : 247
    Red_Max : 247
    Red_Avg : 243
    Red_Min : 239
    Green : 250
    Green_Max : 250
    Green_Avg : 247
    Green_Min : 245
    Blue : 252
    Blue_Max : 252
    Blue_Avg : 251
    Blue_Min : 251
    ScriptVersion : 1
#>

    [cmdletbinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-las-rgb-information-ur-bilder/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true)][string]$FilePath,
    [int]$PixelX,
    [int]$pixelY,
    [int]$PixelArea = 5 #Provide the area around the pixels you want to know the average from.
    
    )


    begin
    {
        # Create base object.
        $scriptversion = 1

        $PixelObjekt=[ordered]@{

        FilePath      = $([string]$FilePath)
        PixelX        = $([int]$PixelX)
        PixelY        = $([int]$pixelY)
        PixelArea     = $([int]$PixelArea)
        Success       = $([bool]$true)
        ImageWith     = $([int])
        ImageHeight   = $([int])
        Red           = $([int])
        Red_Max       = $([int])
        Red_Avg       = $([int])
        Red_Min       = $([int])
        Green         = $([int])
        Green_Max     = $([int])
        Green_Avg     = $([int])
        Green_Min     = $([int])
        Blue          = $([int])       
        Blue_Max      = $([int])              
        Blue_Avg      = $([int])                 
        Blue_Min      = $([int])
        ScriptVersion = $([int]$scriptversion)
        
        }
        $ImageInfo = New-Object -TypeName psobject -Property $PixelObjekt

        if(!(Test-Path $($ImageInfo.FilePath))){Write-Warning "Unable to find the image $($ImageInfo.ImageInfo)"; $ImageInfo.Success = $false;}
    }

    PROCESS{

        if ($ImageInfo.Success){
            Write-Verbose "$($MyInvocation.InvocationName):: Processing Image"
                
                Add-Type -AssemblyName System.Drawing
                $MyBitmapImage = [System.Drawing.Bitmap]::FromFile($ImageInfo.FilePath)

                $ImageInfo.ImageHeight = $MyBitmapImage.Height
                $ImageInfo.ImageWith   = $MyBitmapImage.Width

                # Define max / min area to get the average
                $MinX = $PixelX - $PixelArea
                $MaxX = $pixelX + $PixelArea
                $Miny = $pixelY - $PixelArea
                $MaXy = $pixelY + $PixelArea
            
                Write-Verbose "$($MyInvocation.InvocationName):: MinX = $MinX, MaxX = $MaxX, MinY = $minY, MaxY = $MaXy"
            
                # Loading image information

                if ($MaxX -le $MyBitmapImage.Width -and $MaXy -le $MyBitmapImage.Height -and $MinX -ge 0 -and $minY -ge 0)
                {
                    Write-Verbose "$($MyInvocation.InvocationName):: Selected pixels are within the image size" 
                    
                        # This section will only run if selection was within the image area
                    $xValue = $MinX
                    $yValue = $Miny
                        $summa = while ($xValue -le $MaxX -and $yValue -le $MaXy){
        
                                        while ($xValue -le $MaxX)                                        
                                        {
        
                                            $MyBitmapImage.GetPixel($xValue,$yValue)
        
                                            $xValue++
                                        }
                                $xValue = $MinX
                                $yValue++
                                
                                }
                      
                      $tmpImage = $MyBitmapImage.GetPixel($PixelX, $PixelY)
                      $ImageInfo.Red     = [int]$tmpImage.r
                      $ImageInfo.Green   = [int]$tmpImage.g
                      $ImageInfo.Blue    = [int]$tmpImage.b
                        
                      $ImageInfo.Red_Avg   = [int]($summa.r | Measure-Object -Average | Select-Object -ExpandProperty Average)
                      $ImageInfo.Green_Avg = [int]($summa.g | Measure-Object -Average | Select-Object -ExpandProperty Average)
                      $ImageInfo.Blue_Avg  = [int]($summa.b | Measure-Object -Average | Select-Object -ExpandProperty Average)                      
                      $ImageInfo.Red_Max   = [int]($summa.r | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum)
                      $ImageInfo.Green_Max = [int]($summa.g | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum)
                      $ImageInfo.Blue_Max  = [int]($summa.b | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum)
                      $ImageInfo.Red_Min   = [int]($summa.r | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum)
                      $ImageInfo.Green_Min = [int]($summa.g | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum)
                      $ImageInfo.Blue_Min  = [int]($summa.b | Measure-Object -Minimum | Select-Object -ExpandProperty Minimum)


                      $MyBitmapImage.Dispose()
                } 
                
                else  # Area selected was outside the image

                {
                Write-Warning "The provide X and Y are not within the images resolution"
                $ImageInfo.Success = $false

                }

        
        }
        else
        {
            Write-Verbose "$($MyInvocation.InvocationName):: Unable to find the file $($ImageInfo.imageinfo)"
            
        }
        
    }

    END
    {
            return $ImageInfo
               
    }


} # end function Read-MJImageRGBPixel
 

Function Get-MJVeraBackup{
<#
.Synopsis
   Downloads a backup of your vera controller.
.DESCRIPTION
   This will download an backup of your vera controller and save it as a tgz filese
   Created by Ispep
   Added 2016-06-07
   WWW.Automatiserar.se
.EXAMPLE
    Get-MJVeraBackup -VeraIP VERA -DestinationPath C:\temp\
 
    Filepath FileName Size CreationTime
    -------- -------- ---- ------------
    C:\temp\VeraBackup-2016-06-07-17_27_26.tgz VeraBackup-2016-06-07-17_27_26.tgz 517025 2016-06-07 17:27:26
 
.EXAMPLE
    Get-MJVeraBackup -VeraIP VERA -DestinationPath C:\temp\ -RequireLogin -VeraCredential (Get-Credential)
 
    Filepath FileName Size CreationTime
    -------- -------- ---- ------------
    C:\temp\VeraBackup-2016-06-07-17_29_08.tgz VeraBackup-2016-06-07-17_29_08.tgz 517023 2016-06-07 17:29:08
 
.EXAMPLE
    Get-MJVeraBackup -VeraIP VERA -DestinationPath C:\temp\ -Verbose
 
    VERBOSE: Get-MJVeraBackup:: Beginning function: Download backup from VERA
    VERBOSE: Get-MJVeraBackup:: Data will be gathered from the following URL: http://VERA/cgi-bin/cmh/backup.sh
    VERBOSE: Get-MJVeraBackup:: VERA responding on ping
    VERBOSE: Get-MJVeraBackup:: File path "C:\temp\" exists
    VERBOSE: Get-MJVeraBackup:: Joining path and downloading data from vera
    VERBOSE: Get-MJVeraBackup:: Downloading backup from VERA without username or password
    VERBOSE: Get-MJVeraBackup:: Download successful, creating object and returning it to the pipe
 
    Filepath FileName Size CreationTime
    -------- -------- ---- ------------
    C:\temp\VeraBackup-2016-06-07-17_30_50.tgz VeraBackup-2016-06-07-17_30_50.tgz 517023 2016-06-07 17:30:50
 
.NOTES
   This component requires you to have a Vera controller.
#>

    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
        [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$DestinationPath,
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
        [System.Management.Automation.PSCredential]$VeraCredential,
        [string]$VeraBackupFileName = "VeraBackup" # Provide the beginning of the filename if �VeraBackup� does not meet your requirements.
    )

    
    if ($RequireLogin.IsPresent){
        if (($VeraCredential.UserName).Length -le 3){
            Write-Error "No credential was provided!"
            break
        } 
        else {
            Write-Verbose "$($MyInvocation.InvocationName):: Username $($VeraCredential.UserName) was ok"
        }
    }
    
    Write-Verbose "$($MyInvocation.InvocationName):: Beginning function: Download backup from $veraIP"
    $VeraPath = "http://" + $veraIP + "/cgi-bin/cmh/backup.sh"
    
    Write-Verbose "$($MyInvocation.InvocationName):: Data will be gathered from the following URL: $veraPath"

        if (Test-Connection $veraIP -Count 1 -ErrorAction SilentlyContinue)
        {
            Write-Verbose "$($MyInvocation.InvocationName):: $VeraIP responding on ping"


            ### Verify if the path where the file going to be saved exist

            if (Test-Path $DestinationPath)
            {
                Write-Verbose "$($MyInvocation.InvocationName):: File path `"$DestinationPath`" exists"
            }
            else 
            {
                Write-Verbose "$($MyInvocation.InvocationName):: The path does not exist, will try to create the following path: $DestinationPath"
                New-Item -Path $DestinationPath -ItemType directory -ErrorVariable FileError | Out-Null

                if ($FileError)
                {
                        Write-Warning "The function $($MyInvocation.InvocationName) was unable to create the path $DestinationPath, exiting function"
                        return $error[0] 
                        break
                       
                }
            
            }

            # Folder created or already existed
                
                ### Trying to download the backup from vera

                 Write-Verbose "$($MyInvocation.InvocationName):: Joining path and downloading data from vera"

                $VeraWebData = New-Object System.Net.WebClient
                $VeraBackupFilename = "$VeraBackupFileName-$(Get-Date -UFormat %Y-%m-%d-%H_%M_%S).tgz"
                $TargetDestination = Join-Path -Path $DestinationPath -ChildPath $VeraBackupFilename 

                    IF ($RequireLogin)
                    {
                            Write-Verbose "$($MyInvocation.InvocationName):: Username was required, will try to use the account $($VeraCredential.UserName)"
                            Write-Verbose "$($MyInvocation.InvocationName):: Will now try to download gzip file to destination $TargetDestination"
                            
                            $VeraWebData.Credentials = $VeraCredential
                            $VeraWebData.Headers.Add([System.Net.HttpRequestHeader]::AcceptEncoding, "gzip")
                            $VeraWebData.DownloadFile($veraPath, $TargetDestination) 
                           
                            # If the download was successful a object with all information about the backup will be returned.
                            if ($?){

                                Write-Verbose "$($MyInvocation.InvocationName):: Download successful, creating object and returning it to the pipe"
                                
                                $Tmp_BackupInfo = Get-ItemProperty $TargetDestination
                                $Tmp_Result = New-Object -TypeName psobject 
                                $Tmp_Result | Add-Member -MemberType NoteProperty -Name "Filepath" -Value $TargetDestination
                                $Tmp_Result | Add-Member -MemberType NoteProperty -Name "FileName" -Value $VeraBackupFilename
                                $Tmp_Result | Add-Member -MemberType NoteProperty -Name "Size"     -Value ($Tmp_BackupInfo.Length)
                                $Tmp_Result | Add-Member -MemberType NoteProperty -Name "CreationTime" -Value ($Tmp_BackupInfo.CreationTime)
                            
                                return $Tmp_Result
                                } 
                                else 
                                {
                                Write-Warning "An error has occurred, something did not go successfully. The error given was:"
                                return $error[0] 
                                }
                    } 
                    ELSE 
                    {                
                        Write-Verbose "$($MyInvocation.InvocationName):: Downloading backup from $veraIP without username or password "                

                        $VeraWebData.Headers.Add([System.Net.HttpRequestHeader]::AcceptEncoding, "gzip")
                        $VeraWebData.DownloadFile($veraPath, $TargetDestination)
                                               
                        if ($?){

                            Write-Verbose "$($MyInvocation.InvocationName):: Download successful, creating object and returning it to the pipe"
                            $Tmp_BackupInfo = Get-ItemProperty $TargetDestination
                            $Tmp_Result = New-Object -TypeName psobject 
                            $Tmp_Result | Add-Member -MemberType NoteProperty -Name "Filepath" -Value $TargetDestination
                            $Tmp_Result | Add-Member -MemberType NoteProperty -Name "FileName" -Value $VeraBackupFilename
                            $Tmp_Result | Add-Member -MemberType NoteProperty -Name "Size"     -Value ($Tmp_BackupInfo.Length)
                            $Tmp_Result | Add-Member -MemberType NoteProperty -Name "CreationTime" -Value ($Tmp_BackupInfo.CreationTime)
                            
                            return $Tmp_Result
                            } 
                            else 
                            {
                            Write-Warning "An error has occurred, something did not go successfully. The error given was:"
                            return $error[0] 
                            }


                    }
        } 
        else 
        {
            Write-Verbose "$($MyInvocation.InvocationName):: Your $VeraIP did not respond to the ping"
            Write-Warning "Unable to connect to $veraIp, this will return an Error to the pipe"
            Write-Error "Unable to connect to $veraip"
        }
    
} # End Function Get-MJVeraBackup

Function Get-MJVeraStatus{
<#
.Synopsis
   This function will extract all information from your Vera controller and create an objects.
.DESCRIPTION
   This function is one of the important commands to extract all info from your Vera controller.
   It will collect, devices, alerts, rooms. It will merge two objects into the �Devices� class to get access to name and room more easy.
   The original device will be found under DeviceRaw
 
   Created by Ispep
   Added 2016-06-07
   WWW.Automatiserar.se
.EXAMPLE
    Get-MJVeraStatus -VeraIP vera
 
    Devices : @{}
    DeviceRaw : @{}
    DeviceVerbose : @{}
    Rooms : @{}
    Scenes : @{}
    Alerts : @{}
    LocalTime : 2016-06-07 23:22:00 N
    visible_devices : [int]
    sensors_not_tripped : [int]
    fwd1 : [string]
    fwd2 : [string]
    Server_Device : [string]
    Server_Device_Alt : [string]
    RA_Server : [string]
    RA_Server_Back : [string]
    Mode : [int]
    mode_change_mode : [int]
    mode_change_time : [int]
    breach_delay : [int]
    mode_change_delay : [int]
    skin : [string]
    temperature : [string]
    City_description : [string]
    country_pk : [string]
    model : [string]
    serial_number : [int]
    Version : [string]
    Device_Num_Next : [int]
    Scene_Num_Next : [int]
    gmt_offset : [int]
    InstalledPlugins : @{}
    usergeofences : @{}
    awayStateAllUserNotAtHome : [int]
    homeStateAnyUserAtHome : [int]
    users : @{}
    ScriptVersion : [int]
 
.EXAMPLE
    Get-MJVeraStatus -VeraIP vera -RequireLogin -VeraCredential (Get-Credential)
 
    Devices : @{}
    DeviceRaw : @{}
    Rooms : @{}
    Scenes : @{}
    Alerts : @{}
    LocalTime : 2016-06-07 22:03:33 D
    visible_devices : 8
    sensors_not_tripped : 4
    fwd1 : *URL to veras service*
    fwd2 : *URL to veras service*
    skin : mios
    temperature : C
    model : MiCasaVerde VeraLite
    serial_number : *[int value]*
    Version : *1.7.760*
    ScriptVersion : 1
.NOTES
   This component requires you to have a Vera controller.
#>


    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
    
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
    
        [System.Management.Automation.PSCredential]$VeraCredential
    )

    $ModuleVersion = 1 # This value will be increased if and when this module gets new functions.

    if ($RequireLogin.IsPresent){
        if (($VeraCredential.UserName).Length -le 3){
            Write-Error "No credential was provided!"
            break
        } 
        else {
            Write-Verbose "$($MyInvocation.InvocationName):: Username $($VeraCredential.UserName) was ok"
        }
    }

    if (!(Test-Connection $VeraIP -Count 1)){Write-Warning "Unable to connect to IP / name: $VeraIP!, will not continue"; break}

    $VeraUrl1 = "http://$($veraIP):3480/data_request?id=status" # url to Veras Device Data
    $veraUrl2 = "http://$($veraIP):3480/data_request?id=sdata"  # url to Veras Device Names
    $veraUrl3 = "http://$($veraIP):3480/data_request?id=lu_user_data2" # url to Veras Device Verbose Info

    if ($RequireLogin)
    {
        # Beginning to check what mode the controller is in, this function will use username and password.
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data with this username: $($VeraCredential.UserName)"

        $VeradataDevices = Invoke-RestMethod -Uri $VeraUrl1 -Method Get -ContentType json -Credential $VeraCredential
        $VeradataNames   = Invoke-RestMethod -Uri $veraUrl2 -Method Get -ContentType json  -Credential $VeraCredential
        $veradataInfo    = Invoke-RestMethod -Uri $veraUrl3 -Method Get -ContentType json  -Credential $VeraCredential
    }

        else 
    
    {
       Write-Verbose "$($MyInvocation.InvocationName):: Requesting data Requesting data without username"
       $VeradataDevices = Invoke-RestMethod -Uri $VeraUrl1 -Method Get -ContentType json 
       $VeradataNames   = Invoke-RestMethod -Uri $veraUrl2 -Method Get -ContentType json
       $veradataInfo    = Invoke-RestMethod -Uri $veraUrl3 -Method Get -ContentType json
    }



    # This object will be returned when the script is done.
    $ObjectToReturn = [ordered]@{
                Devices    = @()
                DeviceRaw  = @()
                DeviceVerbose = @()
                Rooms      = @()
                Scenes     = @()
                Alerts     = @()
                LocalTime           = $VeradataDevices.LocalTime
                visible_devices     = $VeradataDevices.visible_devices
                sensors_not_tripped = $VeradataDevices.sensors_not_tripped
                fwd1                = $VeradataNames.fwd1
                fwd2                = $VeradataNames.fwd2
                Server_Device       = [string]
                Server_Device_Alt   = [string]
                RA_Server           = [string]
                RA_Server_Back      = [string]
                Mode                = [int]
                mode_change_mode    = [string]
                mode_change_time    = [string]
                breach_delay        = [int]        
                mode_change_delay   = [int]  
                skin                = $VeradataNames.skin
                temperature         = $VeradataNames.temperature
                City_description    = [string]
                country_pk          = [int]
                model               = $VeradataNames.model
                serial_number       = $VeradataNames.serial_number
                Version             = $VeradataNames.version
                Device_Num_Next     = [int] 
                Scene_Num_Next      = $veradataInfo.Scene_Num_Next
                gmt_offset          = $veradataInfo.gmt_offset
                InstalledPlugins    = @()  
                usergeofences       = @()
                awayStateAllUserNotAtHome = [int]
                homeStateAnyUserAtHome  = [int]  
                users               = @()
                ScriptVersion       = $ModuleVersion # This value is used to determine when a newer version installed
    
    

    }
    
    $MainStatus = New-Object -TypeName psobject -Property $ObjectToReturn
    
    foreach ($device in ($VeradataDevices.devices)){

    $MainStatus.DeviceRaw += $device
    Write-Verbose "$($MyInvocation.InvocationName):: Searching for name om $($device.id)" 

    $Tmp_VeraDevice = $VeradataNames.devices | Where-Object {$_.id -eq $device.id}
                  
    Write-Verbose "$($MyInvocation.InvocationName):: Found matches with id $($device.id)"   

        if ($($(($Tmp_VeraDevice).psobject.Properties).count) -ge 4){
        
        # this function will connect the two objects into one.

       $Tmp_VeraDevice.psobject.Properties| Select-Object -Property "name", "value" | Where-Object {$_.name -ne "id"} | ForEach-Object {
        
        $tmp = $_        
        $device | Add-Member -MemberType NoteProperty -Name $($tmp.name) -Value $($tmp.value) -ErrorAction SilentlyContinue # this will ignore that some values are duplicated
        
            if (!($?)){Write-Verbose "[ISSUE] - Will not merge `"$($tmp.name)`" On ID $($Tmp_VeraDevice.id), The name conflicts with a current name. The value for status is: `"$($tmp.value)`""}
                                           
       }
    $MainStatus.Devices += $device
    } # End merge two devices

} # End Foreach loop

$MainStatus.Rooms   = $VeradataNames.rooms
$MainStatus.Scenes  = $VeradataNames.scenes
$MainStatus.Alerts  = $VeradataDevices.alerts
$MainStatus.DeviceVerbose = $veradataInfo.devices
$MainStatus.InstalledPlugins = $veradataInfo.InstalledPlugins2
$MainStatus.Device_Num_Next  = $veradataInfo.Device_Num_Next
$MainStatus.users            = $veradataInfo.users

$MainStatus.Server_Device      = $veradataInfo.Server_Device
$MainStatus.Server_Device_Alt  = $veradataInfo.Server_Device_Alt
$MainStatus.RA_Server          = $veradataInfo.RA_Server
$MainStatus.RA_Server_Back     = $veradataInfo.RA_Server_Back
$MainStatus.mode_change_mode   = $veradataInfo.mode_change_mode
$MainStatus.mode_change_time   = $veradataInfo.mode_change_time

$MainStatus.City_description  = $veradataInfo.City_description          
$MainStatus.country_pk        = $veradataInfo.country_pk        
$MainStatus.awayStateAllUserNotAtHome = $veradataInfo.awayStateAllUserNotAtHome
$MainStatus.homeStateAnyUserAtHome  = $veradataInfo.homeStateAnyUserAtHome  
$MainStatus.breach_delay      = $veradataInfo.breach_delay        
$MainStatus.mode_change_delay = $veradataInfo.mode_change_delay     
$MainStatus.usergeofences     = $(try {$(ConvertFrom-Json $veradataInfo.usergeofences)} catch {Write-Verbose "$($MyInvocation.InvocationName):: No Geofence Info"}) 
$MainStatus.mode              = $veradataInfo.Mode
return $MainStatus


} # end Get-MJVeraStatus



function Get-MJUnixTimeToNormal{
<#
.Synopsis
   This function is not public, it�s used in my modules to translate date time
.DESCRIPTION
    This function will convert an int unix time to dateTime
   Created by Ispep
   Added 2016-06-07
   WWW.Automatiserar.se
.EXAMPLE
    Get-MJUnixTimeToNormal -UnixTime 1465335719
 
    7 juni 2016 21:41:59
.EXAMPLE
    $myTime = Get-MJUnixTimeToNormal -UnixTime 1465335719
 
    $myTime # Date time object
.NOTES
   This component will only be used inside the module.
#>

[CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    [OutputType([DateTime])]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [int]$UnixTime
    )          # Provide the IP or DNS name to your Vera Controller.


    Write-Verbose "$($MyInvocation.MyCommand):: Will now try to convert `"$UnixTime`" Unix time to Datetime"
    $UnixStartTime = New-Object -Type DateTime -ArgumentList 1970, 1, 1, 0, 0, 0, 0
    [datetime]$Returntime = $UnixStartTime.AddSeconds($UnixTime)
    Write-Verbose "$($MyInvocation.MyCommand):: After translation this was the result $Returntime"
    
    return $Returntime

} # End Get-MJUnixTimeToNormal


function Set-MjVeramode {
<#
.Synopsis
   Sets current mode on Vera Controller with UI7.
.DESCRIPTION
   This will allow you to change mode on your Vera controller.
   Created by Ispep
   Added 2016-06-06
   WWW.Automatiserar.se
.EXAMPLE
 
.EXAMPLE
 
.NOTES
   This component requires you to have a Vera controller.
#>


    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    [OutputType([bool])]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
        [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true)][validateset('Home','Away','Night','Vacation')]$NewVeraMode,
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
    
        [System.Management.Automation.PSCredential]$VeraCredential
    )
    
    # This url REQUIRES 1,2,3,4 in the last index of this string, 1 � 4 represents 1:Home, 2:Away, 3:Night, 4:Vacation
    $VeraChangeModeURL = "http://$($VeraIP):3480/data_request?id=lu_action&serviceId=urn:micasaverde-com:serviceId:HomeAutomationGateway1&action=SetHouseMode&Mode="

    if (!(Test-Connection $VeraIP -Count 1)){Write-Warning "Unable to connect to IP / name: $VeraIP!, will not continue"; break}

    # Gather information about what mode Vera currently running in.
    if ($RequireLogin)
    {
        # Beginning to check what mode the controller is in, this function will use username and password.
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data with this username: $($VeraCredential.UserName)"
        $CurrentVeraMode = Get-MjVeraMode -VeraIP $VeraIP -RequireLogin -VeraCredential $VeraCredential 
         
    } 
    else     
    {
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data Requesting data without username"
        $CurrentVeraMode = Get-MjVeraMode -VeraIP $VeraIP
    }

     Write-Verbose "$($MyInvocation.InvocationName):: `$CurrentVeraMode.mode = $($CurrentVeraMode) `$NewVeraMode = $NewVeraMode"
   
     if ($CurrentVeraMode.mode -eq $NewVeraMode)
            {
                Write-Verbose "$($MyInvocation.InvocationName):: Your controller $veraIP is currently in the mode $CurrentVeraMode , Will not try to change mode to $($NewVeraMode)."
                Write-Warning "Already in the mode $newVeraMode, will not change mode"
                return $false
            }
            else 
            {
               # This switch will convert the readable value to an int value that�s required by vera:s controller
               $VeraModeToSet = switch ($NewVeraMode)
               {
                 'Home'     {1  ; break}
                 'Away'     {2  ; break}
                 'Night'    {3  ; break}
                 'Vacation' {4  ; break}
                  Default   {Write-Error "no value found that matches $NewVeraMode"; break}

               }
                if (!($?)){
                    Write-Error "Will not change mode due to wrong value provided ($NewVeraMode!" 
                    break
                }
                
                   Write-Verbose "$($MyInvocation.InvocationName):: Will now try to change your veras mode to the the following value $($VeraModeTOSet) ($NewVeraMode)"
                   
                   $tmpVeraControllURL = "$($VeraChangeModeURL)" + "$VeraModeToSet"
               
                   # will now try to change Veras Mode to the new value, this will check if the controller requires Login or not
                   if ($RequireLogin)
                   {
                        Write-Verbose "$($MyInvocation.InvocationName):: Will now run with the username $($VeraCredential.UserName) on $VeraIP with http url: $tmpVeraControllURL"
                        $TmpVeraResponse = Invoke-WebRequest -Uri $tmpVeraControllURL  -Credential $VeraCredential 
                   }
                   else
                   {
                        Write-Verbose "$($MyInvocation.InvocationName):: Will now run http command on $VeraIP with http url: $tmpVeraControllURL"
                        $TmpVeraResponse = Invoke-WebRequest -Uri $tmpVeraControllURL
                   }

                   if ($TmpVeraResponse.StatusCode -eq 200){

                        Write-Verbose "$($MyInvocation.InvocationName):: The http command was successful, Return code that was given was $(([xml]($TmpVeraResponse.Content)).SetHouseModeResponse.ok)"
                        return $true
                   }
                   else{
                        # If code that�s not 200 is returned it will throw an error to inform that the command may not have succeeded.
                        Write-Error "The http command did not get corret statuscode!, response code was $($TmpVeraResponse.StatusCode)"
                        return $false 

                   }

            }
   
} # end Set-MJVeraMode

function Get-MJWebCamImage {
<#
.Synopsis
   Connects to webbcams and downloads an image.
.DESCRIPTION
   Connects to webcams and downloads an image to local drive.
   Currently supports login and costume filename.
 
   Created by Ispep
   WWW.Automatiserar.se
.EXAMPLE
    Get-MJWebCamImage -WebcamIP 10.20.30.40 -Destination C:\Temp -SnapshotURL "image/jpeg.cgi"
 
    WebcamIP : 10.20.30.40
    Destination : C:\Temp
    SnapshotURL : image/jpeg.cgi
    Filename : CameraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\Temp\CameraImage_2016-06-08_21-04-22.jpg
    FileSize : 47619
 
.EXAMPLE
    # Rhis will use login on cameras
    Get-MJWebCamImage -WebcamIP 10.20.30.40 -Destination C:\Temp -SnapshotURL "image/jpeg.cgi" -RequireLogin -CamCredential (Get-Credential)
 
    WebcamIP : 10.20.30.40
    Destination : C:\Temp
    SnapshotURL : image/jpeg.cgi
    Filename : CameraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\Temp\CameraImage_2016-06-08_21-04-22.jpg
    FileSize : 47619
 
.NOTES
   This component requires you to have a webcamera.
#>

[CmdletBinding()]
    Param
    (
        # Provide an IP to the camera you would like to download an image from.
        [Parameter(Mandatory=$true,                   
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Provide the IP to the Camera")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$WebcamIP,
        
        [Parameter(Mandatory=$true,                   
                   ValueFromPipelineByPropertyName=$true,
                   HelpMessage="Provide an path to save images")]
        [ValidateNotNull()]
        [ValidateNotNullOrEmpty()]
        [string]$Destination,
        [string]$SnapshotURL = "", # Provide a path to the url in the camera where the image is available
        [string]$Filename = "CameraImage", # This will be the first part of the name of the image.
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
        [System.Management.Automation.PSCredential]$CamCredential
    )

        Write-Verbose "$($MyInvocation.InvocationName):: WebcamIP: $WebcamIP and Destination $Destination"

        # Verify Connection
        if (!(Test-Connection $WebcamIP -Count 1)){Write-Warning "Unable to connect to IP / name: $WebcamIP!, will not continue"; break}

        # Verify that username is present.
        if ($RequireLogin.IsPresent){
            
            if (($CamCredential.UserName).Length -le 3){

                    Write-Error "No credential was provided!"
                    break
            } 
            else {
                Write-Verbose "$($MyInvocation.InvocationName):: Username $($CamCredential.UserName) was ok"
            }
        }

        # Buildning the filepath to use.
        $Tmp_FileName = [string] #$Filename + "_$(get-date -UFormat %Y-%m-%d_%H-%M-%S)" + ".jpg"

        # buildning path to save image to.
        $SavePath = [string] 
        
        # This will verify that the image does not exist already.
            $tmp_Number = 0 
            $tmp_exist  = $true 
            while ($tmp_exist){
                
                $Tmp_FileName = $Filename + "_$(get-date -UFormat %Y-%m-%d_%H-%M-%S)_$tmp_Number" + ".jpg"
                $SavePath= (Join-Path -ChildPath $Tmp_FileName  -Path $Destination) 
                if ((Test-Path $SavePath) -and $tmp_Number -le 10){
                    
                    $tmp_Number++
                } else {
                $tmp_exist = $false # exiting loop if the counter exeeds 10
                }
            }
        

        # Creating webclient.
        $WC = New-Object System.Net.WebClient        
        
        Write-Verbose "$($MyInvocation.InvocationName):: The filepath will be: $SavePath"
        if ($RequireLogin)
        {
           Write-Verbose "$($MyInvocation.InvocationName):: Adding $($CamCredential.UserName) and password to the webclient"
           $WC.Credentials = $CamCredential
         
        } 
        else     
        {
           Write-Verbose "$($MyInvocation.InvocationName):: No username or password required"
           # no username required
        }
        
        # no snapshot url was provided, this will default to one of the default cameras thats available.
        if ($null -eq $SnapshotURL){
            # add dlink, foscam, hikvsion support here!.
        }
        
        if ($SnapshotURL -match "^http"){
            # $snapshoturl shuld be the total path to the camera due to the http in the beginning.
        } 
        else {
            Write-Verbose "$($MyInvocation.InvocationName):: No Http was provided, will try to build the url. Old SnapshotURL = $SnapshotURL"
            
            $FullWebCamSource = "http://" + $((Join-Path -Path $WebcamIP -ChildPath $SnapshotURL).Replace('\','/'))
            Write-Verbose "$($MyInvocation.InvocationName):: Created destination URL: $FullWebCamSource"

        }

        # Verify if the destination exist

        if (!(Test-Path $Destination))
        {
            Write-Warning "Folder $Destination does not exist, should the folder be created?"
            New-Item -Path $Destination -ItemType directory -Confirm | Out-Null
            if ($?){Write-Verbose "Folder $Destination was created OK"} else {Write-Error "Unable to create folder $Destination, no image was saved!"; break}
        }

        # Will build an object to return to the pipe.

        $ObjectToReturn = [ordered]@{
                   WebcamIP     = $WebcamIP
                   Destination  = $Destination
                   SnapshotURL  = $SnapshotURL
                   Filename     = $Filename
                   RequireLogin = if ($RequireLogin){$true}else{$false}
                   WebCamSource = $FullWebCamSource
                   SavePath     = $SavePath                   
                   FileSize     = [int] # This will be added later.
                }
        $ReturnObject = New-Object -TypeName psobject -Property $ObjectToReturn

        

        try 
        {
                    
                  $wc.DownloadFile($FullWebCamSource, $SavePath)   ###
                  if ($?)
                  {
                    
                   # create a object and return all info about the image.
                  $ReturnObject.FileSize = (Get-ItemProperty $SavePath).Length
                  $ReturnObject
                  }
        }
        catch
        {
                Write-Warning "Unable to download image: $SavePath fr�n $FullWebCamSource"
                #Write-Warning $($Error[0]).Exception
                if ($Error[0].Exception -match "(401)"){Write-Error "Your camera requires login credentials, Verify username and password if credential was provided. No image where saved"; break}                
        }
} # End Get-MJWebCamImage


function Save-MJVeraWebCamImage {
<#
.Synopsis
   Connects to Vera controller and collects information about all cameras and saves images.
.DESCRIPTION
   This function will call Get-MJWebCamImage and provide information provided by Get-MJVeraStatus, Images from all webcams will be saved to disk.
   This will provide new objects with information about all images that�s saved with this function.
   2016-06-21 - Added the room the device was found in.
   Currently supports up 10 images / sec (limit with the filename currently)
    
   Created by Ispep
   Added 2016-06-07
   WWW.Automatiserar.se
.EXAMPLE
    Save-MJVeraWebCamImage -VeraIP vera -DestinationPath C:\Temp -Filename VeraImage
 
    WebcamIP : 10.20.30.40
    Destination : C:\Temp
    SnapshotURL : image/jpeg.cgi
    Filename : VeraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\Temp\VeraImage_2016-06-08_23-06-03_3.jpg
    FileSize : 48454
    Room : 1
.EXAMPLE
    Save-MJVeraWebCamImage -VeraIP vera -DestinationPath C:\Temp -Filename VeraImage -RequireLogin -VeraCredential (Get-Credential)
 
    WebcamIP : 10.20.30.40
    Destination : C:\Temp
    SnapshotURL : image/jpeg.cgi
    Filename : VeraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\Temp\VeraImage_2016-06-08_23-07-51_0.jpg
    FileSize : 48498
    Room : 1
.NOTES
   This component requires you to have a Vera controller.
#>



[CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$DestinationPath, # provide the File path where you want files to be saved to
        [string]$Filename = "VeraImage",          
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
        [System.Management.Automation.PSCredential]$VeraCredential
    )
    
    Write-Verbose "$($MyInvocation.InvocationName):: Beginning to collect information form Vera."
    
    $VeraStatusObject = @()

    if ($RequireLogin)
    {
        Write-Verbose "$($MyInvocation.InvocationName):: Login will be used"
        if ($RequireLogin.IsPresent){
            if (($VeraCredential.UserName).Length -le 3){
                Write-Error "No credential was provided!"
                break
            } 
            else {
                Write-Verbose "$($MyInvocation.InvocationName):: Username $($VeraCredential.UserName) was ok"
            }
    }

        
        $VeraStatusObject = Get-MJVeraStatus -VeraIP $VeraIP -RequireLogin -VeraCredential $VeraCredential     
    } 
    else
    {
        Write-Verbose "$($MyInvocation.InvocationName):: No login will be used on $VeraIP"
        $VeraStatusObject = Get-MJVeraStatus -VeraIP $VeraIP 
    }
    
    Write-Verbose "$($MyInvocation.InvocationName):: Sending information into sorting function and extracting all cameras."
    $VeraStatusObject.DeviceVerbose | Where-Object {$_.device_file -match "D_DigitalSecurityCamera"} | ForEach-Object {
    
        $tmpObj = $_ 


        if ($tmpObj.username){
            Write-Verbose "$($MyInvocation.InvocationName):: Username was found on camera $($tmpObj.ip)"
            
            # DUE TO THE SECURE STRING REQUIREMENT THIS WAS ADDED.... The password IS plaintext in VERA, so there�s no workaround except this.... // Ispep...
            $SecureString = New-Object -TypeName System.Security.SecureString
            foreach ($tmpPass in (($tmpObj.password).ToCharArray())){$SecureString.AppendChar($tmpPass)}

            $TMP_ResultObj = Get-MJWebCamImage  -WebcamIP $($tmpObj.ip) -Destination $DestinationPath -Filename $Filename -SnapshotURL $(($tmpObj.states | Where-Object {$_.variable -eq "URL"}).value) -RequireLogin -CamCredential (New-Object System.Management.Automation.PSCredential(($tmpObj.username),($SecureString)))
            $TMP_ResultObj | Add-Member -MemberType NoteProperty -Name "Room" -Value ($tmpObj.room)
            return $TMP_ResultObj
        } else {
            Write-Verbose "$($MyInvocation.InvocationName):: No username or password will be applied to the camera"
            $TMP_ResultObj = Get-MJWebCamImage -WebcamIP $($tmpObj.ip) -Destination $DestinationPath -Filename $Filename -SnapshotURL $(($tmpObj.states | Where-Object {$_.variable -eq "URL"}).value) 
            $TMP_ResultObj | Add-Member -MemberType NoteProperty -Name "Room" -Value ($tmpObj.room)
            return $TMP_ResultObj
        }


    }
} # End Save-MJVeraWebCamImage

function Set-MJVeraDevice {
<#
.Synopsis
   Turn or off devices within vera with a singe command
.DESCRIPTION
   This function will set devices mode in Vera, this function will be limited to a few device types until I tested each class enough
   Created by Ispep
   Added 2016-06-09
   WWW.Automatiserar.se
.EXAMPLE
  # This command will connect to the controller named �Vera� and turn off device 80
  Set-MJVeraDevice -VeraIP vera -DeviceID 80 -Action OFF
    DeviceID : 80
    DeviceName : My Device Name
    DeviceExist : True
    DeviceChangedMode : True
    DevicePowerDevice : True
    deviceType : urn:schemas-upnp-org:device:BinaryLight:1
    CommandSent : True
 
.EXAMPLE
  # If the device is in the current mode no command is sent to the controller.
  Set-MJVeraDevice -VeraIP vera -DeviceID 80 -Action OFF
 
  WARNING: Device 80 / (Lampa Window) - Currently in the same mode as you are trying to set: (OFF).
 
    DeviceID : 80
    DeviceName : My Device Name
    DeviceExist : True
    DeviceChangedMode : False
    DevicePowerDevice : True
    deviceType : urn:schemas-upnp-org:device:BinaryLight:1
    CommandSent : False
.EXAMPLE
  Set-MJVeraDevice -VeraIP vera -DeviceID 10,11,12,33,50 -Action OFF
 
.NOTES
    This requires a Vera Controller with UI7 to work
#>


    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
        [parameter(Mandatory=$true)][string[]]$DeviceID,
        [parameter(Mandatory=$true)][ValidateSet('ON','OFF',ignorecase=$true)][string]$Action, 

        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
        [System.Management.Automation.PSCredential]$VeraCredential
    )

        if (!(Test-Connection $VeraIP -Count 1)){Write-Warning "Unable to connect to IP / name: $VeraIP!, will not continue"; break}

    # Gather information about what mode Vera currently running in.
    $All_Results       = @() # This variable will contain all devices that where searched in the function.
    $tmp_Object        = @() # This will be used later in the function
    $PowerSwitchScheme = "urn:upnp-org:serviceId:SwitchPower1"       # Scheme for switches.
    $PowerDevice_Type  = "urn:schemas-upnp-org:device:BinaryLight:1" # This will narrow the search down to only the correct devices.
    
    
    [string]$tmp_Action = if ($Action -eq "ON"){"1"} elseif ($Action -eq "OFF"){"0"} else {Write-Error "This command does not support this command!";break}

    Write-Verbose "$($MyInvocation.InvocationName):: Begin to verify devices $DeviceID " 

    if ($RequireLogin)
    {
        # Beginning to check what mode the controller is in, this function will use username and password.
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data with this username: $($VeraCredential.UserName)"
        $tmp_Object = Get-MJVeraStatus -VeraIP $VeraIP -RequireLogin -VeraCredential $VeraCredential
    } 
    
    else 
    
    {
        Write-Verbose "$($MyInvocation.InvocationName):: Requesting data Requesting data without username"
        $tmp_Object = Get-MJVeraStatus -VeraIP $VeraIP
    }

    # This will be the object to check

    Write-Verbose "$($MyInvocation.InvocationName):: Will now check This devices: $deviceid"

    foreach ($TMP_DeviceID in $DeviceID){

    # Build the controll string for each device.
    $VeraPowersSwitchURL = "http://$($VeraIP):3480/data_request?id=lu_action&output_format=xml&DeviceNum=$($TMP_DeviceID)&serviceId=$($PowerSwitchScheme)&action=SetTarget&newTargetValue="


    # Crate a object that will get all information added and returned to pipeline, default False
    $TMP_DeviceObject = [ordered]@{
                DeviceID     = [string]$TMP_DeviceID     # DevicesID
                DeviceName   = [string]""           # Name of the device if it exits.
                DeviceExist  = [bool]$false       # true if exists
                DeviceChangedMode = [bool]$false  # true if the function changes mode on device.
                DevicePowerDevice = [bool]$false  # true if Switch
                DeviceType      = [string]""     # this will be the scheme used by the device.
                CommandSent     = [bool]$false   # this will be set to True if a device was controlled with the command
                }

    $ObjectToReturn = New-Object -TypeName psobject -Property $TMP_DeviceObject 
 
    $Tmp_Result = $tmp_Object.DeviceVerbose | Where-Object {$_.id -eq $TMP_DeviceID -and $_.states.service -eq $PowerSwitchScheme -and $_.states.variable -eq "Status" -and $_.device_type -eq "$PowerDevice_Type"}
    if ($Tmp_Result){
        $Tmp_ValueCheck = @() 
        
        # Validating if the device exist
        $Tmp_ValueCheck = $Tmp_Result.states | Where-Object {$_.service -eq $PowerSwitchScheme -and $_.variable -eq "Status"}
    
        if ($Tmp_ValueCheck){
            
            Write-Verbose "$($MyInvocation.InvocationName):: Device are ready to be controlled!"

                  # Are the current value the same as the one the controller currently in?
                  if ($tmp_Action -eq $Tmp_ValueCheck.value){
                    Write-Warning "Device $TMP_DeviceID / ($($Tmp_Result.name)) - Currently in the same mode as you are trying to set: ($Action)."
                    
                    $ObjectToReturn.DeviceExist = $true
                    $ObjectToReturn.DevicePowerDevice = $true
                    $ObjectToReturn.DeviceName = $($Tmp_Result.name)
                    $ObjectToReturn.devicetype  = $($Tmp_Result.device_type)
                    $All_Results += $ObjectToReturn
                    # This will return an false result
                  } 
                  else 
                  {

                     Write-Verbose "$($MyInvocation.InvocationName):: Device $TMP_DeviceID / ($($Tmp_Result.name)) currently is not in the same mode as you are trying to set"
                     Write-Verbose "$($MyInvocation.InvocationName):: Change mode on $TMP_DeviceID ($($Tmp_Result.name)) to $Action"
                     Write-Verbose "$($MyInvocation.InvocationName):: Sending url: $($VeraPowersSwitchURL)$tmp_Action" 

                     $TmpHTTP_Result = Invoke-RestMethod -Uri "$($VeraPowersSwitchURL)$tmp_Action" -Method Get                     
                     
                     Write-Verbose "$($MyInvocation.InvocationName):: Result was $TmpHTTP_Result"

                     $ObjectToReturn.DeviceExist = $true
                     $ObjectToReturn.DevicePowerDevice = $true
                     $ObjectToReturn.DeviceName = $($Tmp_Result.name)
                     $ObjectToReturn.DeviceChangedMode = $true
                     $ObjectToReturn.devicetype  = $($Tmp_Result.device_type)
                     $ObjectToReturn.CommandSent = $true 
                     $All_Results += $ObjectToReturn
                     # This will return an true result
                  }
                
                   
        } else {
            Write-Warning "No Powershwich function was found on device $TMP_DeviceID, name: $($Tmp_Result.name) "
            $ObjectToReturn.DeviceExist = $true
            $ObjectToReturn.DeviceName  = $($Tmp_Result.name)
            $ObjectToReturn.devicetype  = $($Tmp_Result.device_type)
            $All_Results += $ObjectToReturn
            # This will return an false result
        }
   } 
   else { # scheme did not match, will check if device exists.
        $Tmp_MatchOnDeviceID = $tmp_Object.DeviceVerbose | Where-Object {$_.id -eq $TMP_DeviceID}
        
            if ($Tmp_MatchOnDeviceID){
             Write-Warning "No Powershwich function was found on device $($Tmp_MatchOnDeviceID.name) with ID $($Tmp_MatchOnDeviceID.id)"
            $ObjectToReturn.DeviceExist = $true
            $ObjectToReturn.DeviceName  = $($Tmp_MatchOnDeviceID.name)
            $ObjectToReturn.devicetype = $Tmp_MatchOnDeviceID.device_type
            $All_Results += $ObjectToReturn

        } else {

        Write-Warning "No device with ID $TMP_DeviceID was found!"
        $All_Results += $ObjectToReturn
        
        }
        # This will return an false result
   } 

   }

   return $All_Results # returns all info

} # END Set-MJVeraDevice




function Set-MJImageInformation {
<#
.Synopsis
   This will open an image and add information to the image.
.DESCRIPTION
   This function will allow you to paint information into images and then save them for use.
   it�s a part of the module I use for the home automation project with Vera
 
   Created by Ispep
   Added 2016-06-21
   WWW.Automatiserar.se
 
.EXAMPLE
# This will load the image MyImage.jpg and save a new image in path: C:\temp\MyResult.jpg with the date information and 22 Celcius added to the image
 
Set-MJImageInformation -SourceImage C:\Temp\MyImage.jpg -DestinatinPath C:\temp\MyResult.jpg -Information "$(get-date)","22 Celsius"
 
.EXAMPLE
# this will load the image MyImage.jpg and save a new image in path: C:\temp\MyResult.jpg with date and "Motion Detected" information. this info will be saved in the images X 100 and Y 200 with a font size of 12
 
Set-MJImageInformation -SourceImage C:\Temp\MyImage.jpg -DestinatinPath C:\temp\MyResult.jpg -Information "$(get-date)","Motion Detected" -ImageInfoLocationWidth 100 -ImageInfoLocationHeight 200 -FontSize 12
 
 
.NOTES
   This component requires an image to exist before it�s possible to write in the image.
#>

[CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$SourceImage,               # Provide a path to the image you want to uppdate with information.
        [string]$DestinatinPath,            # Provide the path where the image should be saved.
        [string[]]$Information,             # Add the strings you want to add to the image.
        [int]$ImageInfoLocationWidth  = 15, # Provide the Image X location where you want the information to be written.
        [int]$ImageInfoLocationHeight = 10, # Provide the image Y location
        [int]$FontSize = 12,                # This allows you to set the font size
        [int]$RectangleTop     = 80,        # width of the rectangle
        [int]$RectangleRight   = 80,        # height of the rectangle
        [int]$Rectangletransparency = 100   # provide the transparency you want to have on the rectangle
)

     begin {
    
        #Load .net assemblys
        [Reflection.Assembly]::LoadWithPartialName("System.Drawing") | Out-Null
        
        if (!(Test-Path $SourceImage)){Write-Error "Unable to find the file $SourceImage"; break} 
        
        # Load the image file
        $srcImg = [System.Drawing.Image]::FromFile($SourceImage)
        
        # Create an bitmap object
        $bmpFile = new-object System.Drawing.Bitmap([int]($srcImg.width)),([int]($srcImg.height))

        $Image = [System.Drawing.Graphics]::FromImage($bmpFile)
        $Image.SmoothingMode = "AntiAlias"

        # write the image information into the rectangle
        $Rectangle = New-Object Drawing.Rectangle 0, 0, $srcImg.Width, $srcImg.Height 
        $Image.DrawImage($srcImg, $Rectangle, 0, 0, $srcImg.Width, $srcImg.Height, ([Drawing.GraphicsUnit]::Pixel))

     } # end - Begin

     process {
            
            # This section will allow you to change where the information is written.

            $TopWidth  = $(if ($ImageInfoLocationWidth -gt $srcImg.Width){Write-Error "This value is greater than the image with!"; break} else {$ImageInfoLocationWidth})    # sets the image location with
            $TopHeight = $(if ($ImageInfoLocationWidth -gt $srcImg.Width){Write-Error "This value is greater than the image height!"; break} else {$ImageInfoLocationHeight}) # sets the image location height
        
            $StartLocation = $TopHeight  # This variable is used to get the start location for all information.
        
                # This section will try to resolve how big the rectangle should be.
            
                $RectangleTextWidth = 0
                $RectangleHeight    = (($Information.Count) * ($FontSize + 7)) -as [int]
                
                # This will check all text and add make the rectangle the needed width
                foreach ($tmpinfo in $Information){
                    
                    if ($RectangleTextWidth -le (($($tmpinfo.Length) * 10) * ($FontSize/12))){
                        
                        $RectangleTextWidth = (($($tmpinfo.Length) * 10) * ($FontSize/12)) -as [int]
                    }
                    
                    Write-Verbose "$($MyInvocation.InvocationName)::[Foreach] The text length is $($tmpinfo.length), the variable is $RectangleTextWidth"             
                    Write-Verbose "$($MyInvocation.InvocationName)::[Foreach] Verify if the text will fit into the image, text: $($RectangleTextWidth) vs $($srcImg.width)"
                    
                    # If the information risks to be written outside the image there will be a warning, but the image will still be written.

                    if (($ImageInfoLocationWidth + $RectangleTextWidth) -ge ($srcImg.Width)){

                        Write-Warning "Some text will be written outside this image!"
                        Write-Verbose "$($MyInvocation.InvocationName)::[if-True] the text will end in this index: $($ImageInfoLocationWidth + $RectangleTextWidth), the image is only $($srcImg.Width)"
                    }
                } # end foreach
        
          Write-Verbose "$($MyInvocation.InvocationName):: The information will be written at indexes $ImageInfoLocationWidth, $ImageInfoLocationHeight, $RectangleTextWidth, $RectangleHeight"    
         
         $Brush = New-Object Drawing.SolidBrush ([System.Drawing.Color]::FromArgb($rectangletransparency,0,0,0))
         $Image.FillRectangle($Brush, $ImageInfoLocationWidth, $ImageInfoLocationHeight, $RectangleTextWidth, $RectangleHeight)

        # This part will add information to the image.
        ForEach ($TMPInfo in $Information){

        $Font = new-object System.Drawing.Font("Verdana", $FontSize)
        $Brush = New-Object Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 255, 255,255)) # This will set the text color White
        $Image.DrawString("$TMPInfo", $Font, $Brush, $TopWidth , $StartLocation)

        $StartLocation += ($FontSize + 5)

        }

        $srcImg.Dispose()
        $bmpFile.save($DestinatinPath, [System.Drawing.Imaging.ImageFormat]::jpeg)
        $bmpFile.Dispose()
        

    } # Process
    end {

    return $true 


    } # end

} # END Set-MJImageInformation



function Save-MJVeraImageWithInfo {
<#
.Synopsis
   Saves all images from vera with all sensors in that room.
.DESCRIPTION
   This will allow you to add more information to your vera device.
   Created by Ispep
   Added 2016-06-21
   WWW.Automatiserar.se
.EXAMPLE
    # This will download and add all sensor information to the image in Vera.
    Save-MJVeraImageWithInfo -VeraIP VeraIP -Destinationpath C:\temp
 
    WebcamIP : 10.20.30.40
    Destination : C:\temp
    SnapshotURL : image/jpeg.cgi
    Filename : VeraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\temp\VeraImage_2016-06-21_21-30-27_3.jpg
    FileSize : 49211
    Room : 13
 
.EXAMPLE
    # This will download and add all sensor information to the image in Vera.
    Save-MJVeraImageWithInfo -VeraIP VeraIP -Destinationpath C:\temp -Infotransparency 255
 
    WebcamIP : 10.20.30.40
    Destination : C:\temp
    SnapshotURL : image/jpeg.cgi
    Filename : VeraImage
    RequireLogin : True
    WebCamSource : http://10.20.30.40/image/jpeg.cgi
    SavePath : C:\temp\VeraImage_2016-06-21_21-30-27_3.jpg
    FileSize : 49211
    Room : 13
 
.NOTES
   This component requires you to have a Vera controller.
#>


    [CmdletBinding(PositionalBinding=$false,
                  HelpUri = 'http://www.automatiserar.se/powershell-modul-for-hemautomation/',
                  ConfirmImpact='Medium')]
    param(
    [Parameter(Mandatory=$true, 
                   ValueFromPipeline=$true,
                   ValueFromPipelineByPropertyName=$true, 
                   ValueFromRemainingArguments=$false, 
                   Position=0)]
        [ValidateNotNullOrEmpty()]
        [string]$VeraIP,          # Provide the IP or DNS name to your Vera Controller.
        [switch]$RequireLogin,    # If you require your controller to apply login use this switch and provide credential to your vera..
        [string]$Destinationpath, # Provide the path where you want the images to be saved.
        [int]$FontSize = 10,      # Provude the fontsize
        [int]$Infotransparency = 125, # Sets the transperency to 50% min 0 max 255 for the black
        [System.Management.Automation.PSCredential]$VeraCredential
    )
    begin {
        if (!(Test-Connection $VeraIP -Count 1)){Write-Warning "Unable to connect to IP / name: $VeraIP!, will not continue"; break}
        
        # verify Destination folder and creates it if needed.
        if (!(Test-Path $Destinationpath)){
            Write-Warning "Unable to find folder $Destinationpath, will create it now."
            New-Item -Path $Destinationpath -ItemType directory | Out-Null
            if (!($?)){
                Write-Error "Unable to create a folder in path $Destinationpath"
                break 
            }
        }
        $AllImages = @() # Create an empty object
        $AllResults = @() # This will provide info about all images.
        $AllVeraDevices = @() 
        # Gather information about what mode Vera currently running in.
        if ($RequireLogin)
        {
            # Beginning to check what mode the controller is in, this function will use username and password.
        
            Write-Verbose "$($MyInvocation.InvocationName):: Requesting data with this username: $($VeraCredential.UserName)"
            $AllImages = Save-MJVeraWebCamImage -VeraIP $VeraIP -RequireLogin -VeraCredential $VeraCredential 
            $AllVeraDevices = Get-MJVeraStatus -VeraIP $VeraIP -RequireLogin -VeraCredential $VeraCredential
        } 
        else     
        {
            Write-Verbose "$($MyInvocation.InvocationName):: Requesting data Requesting data without username"
             $AllImages =  Save-MJVeraWebCamImage -VeraIP $VeraIP -DestinationPath $Destinationpath
             $AllVeraDevices = Get-MJVeraStatus -VeraIP $VeraIP
        }

    }
    process {

        foreach ($Imgfile in $allImages){
            
            $InfoToadd = @() # This is the information to add to the image.
            $DevicesInRoom = $AllVeraDevices.DeviceVerbose | Where-Object {$_.room -eq $($Imgfile.Room)}
            
            foreach ($DeviceInRoom in $DevicesInRoom){
            
                switch ($DeviceInRoom.device_type){
                    'urn:schemas-micasaverde-com:device:HumiditySensor:1'    {$InfoToadd += "$($DeviceInRoom.name): $($DeviceInRoom.states | Where-Object {$_ -match "urn:micasaverde-com:serviceId:HumiditySensor1"} | Select-Object -ExpandProperty value)"}
                    'urn:schemas-micasaverde-com:device:LightSensor:1'       {$InfoToadd += "$($DeviceInRoom.name): $($DeviceInRoom.states | Where-Object {$_ -match "urn:micasaverde-com:serviceId:LightSensor1"} | Select-Object -ExpandProperty value)"}
                    'urn:schemas-micasaverde-com:device:TemperatureSensor:1' {$InfoToadd += "$($DeviceInRoom.name): $($DeviceInRoom.states | Where-Object {$_ -match "urn:upnp-org:serviceId:TemperatureSensor1" -and $_ -match "CurrentTemperature"}| Select-Object -ExpandProperty value)"}
                    'urn:schemas-micasaverde-com:device:DoorSensor:1'        {$InfoToadd += "$($DeviceInRoom.name): $(if ($($DeviceInRoom.states | Where-Object {$_ -match "urn:micasaverde-com:serviceId:SecuritySensor1" -and $_ -match "Tripped"} | Select-Object -ExpandProperty value) -eq 0){"Closed"} else {"OPEN"})"}
                    'urn:schemas-micasaverde-com:device:MotionSensor:1'      {$InfoToadd += "$($DeviceInRoom.name): $(if ($($DeviceInRoom.states | Where-Object {$_ -match "urn:micasaverde-com:serviceId:SecuritySensor1" -and $_ -match "Tripped"} | Select-Object -ExpandProperty value) -eq 0){"NO"} else {"YES"})"}
                    Default {Write-Verbose "$($MyInvocation.InvocationName):: This device was not configured in this function $($deviceInRoom.device_type)"}

                }
            
            }
            
            Set-MJImageInformation -SourceImage "$($Imgfile.SavePath)" -DestinatinPath "$($Imgfile.SavePath)" -Information $InfoToadd -Rectangletransparency $Infotransparency
            

            
            $AllResults += $Imgfile 


        }

    }


    end {

        return $AllResults
    }


} # END Save-MJVeraImageWithInfo