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 -VeraCredential (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.
   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
 
.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
.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)}

            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)))

        } else {
            Write-Verbose "$($MyInvocation.InvocationName):: No username or password will be applied to the camera"
            Get-MJWebCamImage -WebcamIP $($tmpObj.ip) -Destination $DestinationPath -Filename $Filename -SnapshotURL $(($tmpObj.states | Where-Object {$_.variable -eq "URL"}).value) 

        }


    }
} # 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