AutomatiserarSE.psm1

#
# Module 'AutomatiserarSE'
#
# Created by: Ispep
#
# Generated on: 2017-03-11
#
# Blog www.automatiserar.se
#

function Set-MjInfluxPostDataStructure(){
<#
.Synopsis
   This changes the array to an string for InfluxDB
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
   This function is used to build the data format that Influx requires
   * Hidden function, used by post data function
.EXAMPLE
   #
   Set-MjInfluxPostDataStructure -DataToParse $("Temperature=11.23","Luftfuktighet=100")
 
   Returns:
   Temperature=11.23,Luftfuktighet=100
 
.EXAMPLE
   Another example of how to use this cmdlet
#>

[cmdletbinding()]
param(
[Parameter(Mandatory=$true)][array]$DataToParse

)
    begin
    {
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Convert Array to string] :: $DataToParse"
    }

    process
    {
            # Create an empty string
            $tmp_influxdatainfo = "" 
            
            foreach ($obj in $DataToParse){
            
            Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Extract Info ] :: $obj"
            
            # verify that "," and spaces are not in the array provided
            if ($obj.Contains(",") -or $obj.Contains(" "))
            {
                Write-Error "This character `",`" or Space is not allowed in `"influxdataInfo`"!"
                break
            } 
            
            else 
            
            {
                Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Current Data ] :: $tmp_influxdatainfo"
                Write-Verbose "[$($MyInvocation.InvocationName)] :: [ ADD Data ] :: $obj"
                
                $tmp_influxdatainfo += "$obj,"
                
            }

            Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Data in tmp_influxdatainfo] :: $tmp_influxdatainfo"
            

        }

    }

    end
    {
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Replace last `",`"] :: [ ToDo ] :: $tmp_influxdatainfo"
        
        $tmp_influxdatainfo = $tmp_influxdatainfo.Substring(0,$($tmp_influxdatainfo.LastIndexOf(",")))
        
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Replace last `",`"] :: [ Done ] :: $tmp_influxdatainfo"

        return $tmp_influxdatainfo
    }


}


function Create-MJinfluxArray(){
<#
.Synopsis
   Build an array of objects, this data can be used in the Send-MJInfluxData
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
    This function will get an array of data, it will try to parse it with the following structure:
     
    It will replace all spaces with "_", this to avoid influxdatabase post structure.
 
    row1 : maintag
    row2 : taginfo
    row3 : value
    row4 : datetime
     
    "Maintag||||IP=10.20.30.40,Firmware=3.2||||WifiSignal=-22,Temperature=22.3,Laddning=4.2,AntalMS=1232||||2016-08-16 13:06:22.131"
     
    This is an exampel the data will be changed:
    ESP8266-NR12||||IP=10.20.30.40,Firmware=2.1||||WifiSignal=-89,Temperatur=24.94,Laddning=4.25,AntalMS=4213||||2016-08-16 13:06:22.131
 
.EXAMPLE
   
  Send-MJInfluxData -InfluxServer YourComputer -databaseName Automatiserarse -BulkData $($ArrayPostData)
 
  This is the values in the $ArrayPostData:
    
      ESP8266-NR12||||IP=10.20.30.40,Firmware=2.1||||WifiSignal=-84,Temperatur=12.81,Laddning=0.03,AntalMS=2456||||2016-08-18 02:06:11.621
      ESP8266-NR12||||IP=10.20.30.40,Firmware=2.1||||WifiSignal=-84,Temperatur=12.88,Laddning=0.03,AntalMS=2482||||2016-08-18 02:11:04.365
 
.EXAMPLE
   Another example of how to use this cmdlet
#>

[cmdletbinding()]
param(
[Parameter(Mandatory=$true)]$DataToProcess,
[int]$MaxProcessLimit = 5000 # The default limit for an array post to Influxdb default
)

    begin
    {
        Write-Verbose "[$($MyInvocation.InvocationName)]::[ Function version 1.0 ]"
        Write-Verbose "[$($MyInvocation.InvocationName)]::[ Number of rows] $($DataToProcess.count)"
        [array]$tmp_returnObject = @() # this will be returned later
    }

    process
    {
        if ($DataToProcess.count -gt $MaxProcessLimit){
            
             Write-Verbose "[$($MyInvocation.InvocationName)]::[ More then the default array size! ]"
             Write-Error "This array of data is to big for InfluxDB default (more then $MaxProcessLimit) your data was $($DataToProcess.count), use `"MaxProcessLimit`" if you have increased this number in your database" 
             break 
        } 
        else 
        {
            Write-Verbose "[$($MyInvocation.InvocationName)]::[ Array are smaler than then the limit] $MaxProcessLimit"
        }
    
        # begin to process data an change the structure to the allowed data format.

         # Row 1 : until "||||" Anything until the first |||| will be "MainTag" "MyComputername||||
         # Row 2 : Until "||||" Untill the second is found in the string the values vill be added as TagInfo "info=yes","moreInfo=no"||||
         # Row 3 : Until "||||" When the third is found the data vill be added as values" "temperature=22.3","sun=22"||||
         # Row 4 : utill "||||" after the forth it will try to convert the value to unix time format "2016-08-16 13:06:22.131"
         
         Write-Verbose "[$($MyInvocation.InvocationName)]::[ Try to split data ]"
         
         foreach ($tmprad in $DataToProcess){
         
         if ($tmprad -match '(?<Mantag>.*)\|\|\|\|(?<Taginfo>.*)\|\|\|\|(?<values>.*)\|\|\|\|(?<date>.*)'){

            Write-Verbose "[$($MyInvocation.InvocationName)][ Found Row ]"
            $Matches.date =  "$($(get-date $($([datetime]$Matches.date).AddHours(-1)) -UFormat %s).Split(",")[0])000000000" 
            
            $tmp_string = "$($Matches.Mantag),$($matches.taginfo) $($Matches.values) $($matches.date)`n"
            $tmp_returnObject += $tmp_string

            Write-Verbose "[$($MyInvocation.InvocationName)] $tmp_string"
         }
         else
         {
            Write-Warning "Unable to find a match for the row $tmprad"
         }

         }
         
    }

    end
    {
        return $tmp_returnObject
    }

}




function Send-MJInfluxData(){
<#
.Synopsis
   Send data to InfluxDB databases
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
   This function verify that your data is provided with the structure required by InfluxDB
   AVOID to use SPACE and "," those could make your input break.
   if data are posted ok, you will get "True" in response
   Current version does not allow for manual input of date!
 
   V1.1 - Added Bulkdata
        This will allow a maximum of 5000 objects to be posted to Influx. It requires that the time is added before
        and that $MainDataTag, TagInfo and Values is empty. othervise bulkdata is ignored
         
 
.EXAMPLE
   # Send information to database
 
   Send-MJInfluxData -InfluxServer MyInfluxServer -databaseName Automatiserarse -MainDataTag "powershell" -TagInfo $("host=MyCompyter","Type=WIFI","OS=Windows10") -Value "value1=22.2,value2=12.4"
 
   True
 
.EXAMPLE
   Another example of how to use this cmdlet
#>

[cmdletbinding()]
param(
[Parameter(Mandatory=$true)][string]$InfluxServer,
[Parameter(Mandatory=$true)][string]$databaseName,
[Parameter(Mandatory=$false)][string]$MainDataTag,
[Parameter(Mandatory=$false)][array]$TagInfo,     # example $("host=demo","ip=10.20.30.40")
[Parameter(Mandatory=$false)][array]$Values,      # example $("temperature=11","light=229")
[parameter(Mandatory=$false)][array]$BulkData,    # This allows 5000 objects to be written to the database.
[switch]$https,
[int]$port = 8086 
)

    begin
    {
        Write-Verbose "[$($MyInvocation.InvocationName):: [Function - Version 1.1]"
        # URL to post data to.
        
        [string]$tmp_httpmode = (set-mjInfluxhttps -https $https)
        
        $tmp_baseUrl = "$($tmp_httpmode)://$($InfluxServer):$($port)/write?db=$($databaseName)"
        
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ post URL ] :: $tmp_baseUrl"

    }

    process
    {
        # Create a list with "," to split objects
        $tmp_influxdatainfo = ""

        # Define this as array, this will be posted to Influx later
        $Tmp_UrlBody = @()       
        
                # This is added in version 1.1 to support both bulk and singel input.
                if ($MainDataTag -ne $null -and $TagInfo -ne $null -and $Values -ne $null)
                {
                    $tmp_influxdatainfo = Set-MjInfluxPostDataStructure -DataToParse $TagInfo
                    
                        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Data att Posta ] :: $tmp_influxdatainfo"
            
                        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Values provided ] :: $Values"
                    
                        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Singel data post ] :: $Tmp_UrlBody"
                    
                        
                    
                    # Remember to use the last " " after to let Influx set the time!

                    $Tmp_values = Set-MjInfluxPostDataStructure -DataToParse $Values

                        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Values returned ] :: $Tmp_values"

                    $Tmp_UrlBody = $("$($MainDataTag),$tmp_influxdatainfo $($Tmp_values.trim()) ")

                }
                # if there is more than one row in bulkdata this will be used.
                elseif($BulkData.count -gt 1)
                {
                    
                    Write-Verbose "[$($MyInvocation.InvocationName)] :: [ bulkdata ] :: $($bulkdata.Count)"
                    $Tmp_UrlBody = Create-MJinfluxArray($BulkData)

                }
                else
                {
                    Write-Error "Data provided did not match any post filter! You need to provide `"bulkdata`" with an array OR Maindatatag, TagInfo and Values with data"
                    break
                }
            

         # Post data to InfluxDB
         try
         {
            $tmp_result = Invoke-RestMethod -Uri $tmp_baseUrl -Method Post -Body $Tmp_UrlBody
            return $true
         }
         catch
         {
            Write-Warning $($Error[0].ErrorDetails.Message)
            Write-Error "unable to send your data to database $databaseName"
            
            return $false
         }
    }

    end
    {

    }


}

function Drop-mjInfluxDB(){
<#
.Synopsis
   Drops an InfluxDB Database
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
   This command will drop an array of INFLUX databases. It will first check if the database exist.
   it supports database arrays if needed.
.EXAMPLE
   #
   Drop-mjInfluxDB -InfluxServer MyInfluxServer -databaseName "Automatiserarse","demodemo"
 
    DatabasesToRemove : {Automatiserarse, demodemo}
    RemovedItems : {Automatiserarse, demodemo}
    RemovedItemCount : 2
    Version : 1
    HttpMode : http
    NotFoundDatabases : {}
 
.EXAMPLE
   #
    Drop-mjInfluxDB -InfluxServer MyInfluxServer -databaseName "Automatiserarse","demodemo" -confirmRemove -Verbose
 
    DatabasesToRemove : {Automatiserarse, demodemo}
    RemovedItems : {Automatiserarse, demodemo}
    RemovedItemCount : 2
    Version : 1
    HttpMode : http
    NotFoundDatabases : {}
 
#>

[cmdletbinding()]
param(
[Parameter(Mandatory=$true)][string]$InfluxServer,
[Parameter(Mandatory=$true)][array]$databaseNames,
[bool]$https,
[int]$port = 8086,
[switch]$confirmRemove
)

    begin
    {
        # Main functions Version, this is returned from the function with the "Version" label
        $tmp_Drop_mjInfluxDBVersion = 1 

        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Will try to drop ] $($databaseNames)"

        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Check http mode ]"
        [string]$tmp_httpmode = (set-mjInfluxhttps -https $https)

        # Url to use when removing databases
        $tmp_baseUrl = "$($tmp_httpmode)://$($InfluxServer):$port/query"

         Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Base URL ] :: $tmp_baseUrl"
         
         # This object will be returned
         $tmp_InfluxremovedObjects = New-Object psobject -Property ([ordered]@{
            DatabasesToRemove = [array]$databaseNames
            RemovedItems      = [array]@()
            RemovedItemCount  = [int]0
            Version           = [int]$tmp_Drop_mjInfluxDBVersion
            HttpMode          = [string]$tmp_httpmode
            NotFoundDatabases = [array]@() 
         })

    }

    process
    {
     # Check if the database exist
        Write-Verbose "[$($MyInvocation.InvocationName)] :: Try to get all current databases"        
        $Tmp_CurrentDatabases = List-mjInfluxDB -InfluxServer $InfluxServer -https $https 

        # If this value is false, there where a problem with the connection
        if (($Tmp_CurrentDatabases.Success) -eq $false)
        {
            Write-Error "Unable to connect to server $InfluxServer to find any databases"
            break 
        }

        # Unless the command connects to the database this will not continue
        if ($Tmp_CurrentDatabases.Success){
           
           Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Checked for databases ] :: OK"

          # check all databases in the array.
          foreach ($tmp_database in $databaseNames)
          {
             Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Check if database exist ] :: $tmp_database "

                ###
                ### ### Check if databas where found before removing.
                ###
                $tmp_matchDB = $false

                # Check all databases
                foreach ($tmp_db in $Tmp_CurrentDatabases.Databases){
                    Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Check if database match ] $tmp_database | $tmp_db"
                    if ($tmp_db -cmatch $tmp_database){$tmp_matchDB = $true}
                    
                }
                
                ### found match - ready to remove.
                if ($tmp_matchDB){
                    
                    Write-Warning "removing $tmp_database"

                    
                      if ($confirmRemove)
                      {
                         $tmp_true = $true # this will loop untill done
                         [string]$tmp_answer = Read-Host "Remove database $tmp_db from $($InfluxServer)? Y/N:"
                         
                         # Loop until Y / N is answerd
                         while ($tmp_true)
                         {
                           
                            if ("N" -eq $($tmp_answer))
                            {
                                Write-Warning "Will not remove $tmp_database, breaking out"
                                break
                            }
                         
                            elseif("Y" -eq $($tmp_answer))
                            {
                                $tmp_true = $false                         
                            }
                            else 
                            {
                                [string]$tmp_answer = Read-Host "Wrong answer! Remove database $tmp_database from $($InfluxServer)? Y/N:"
                            }
                         }


                      }
                    try
                    {
                                              
                    $tmp_result = Invoke-RestMethod -Uri $tmp_baseUrl -Method Post -Body $("q=DROP DATABASE $($tmp_database)") 
                    $tmp_InfluxremovedObjects.RemovedItems += $tmp_database
                    }
                    catch
                    {
                        Write-Error "Something did not work ok! will not remove anymore databases"
                        break
                    }

                }
                # No databases where found with the name provided
                else 
                {
                    Write-Warning "Unable to find any databases on $InfluxServer with the name `"$tmp_database`""
                    $tmp_InfluxremovedObjects.NotFoundDatabases += $tmp_database
                }
          }
      }
       
      else
      
      {
        Write-Warning "No Databases where found on the server `"$InfluxServer`", breaking the function"
        break
      }

     
        
    }

    end
    {
      $tmp_InfluxremovedObjects.RemovedItemCount = $($tmp_InfluxremovedObjects.RemovedItems).count
      return $tmp_InfluxremovedObjects
    }



}

function List-mjInfluxDB(){
<#
.Synopsis
   This will show all influx databases.
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
   With this function an array with all databases and the status of the command is returned.
   To verify if the command where successful check the bool flag "Success".
.EXAMPLE
    List-mjInfluxDB -InfluxServer MyInfluxServer
 
Returns:
 
Databases : {_internal, Automatiserarse}
Server : MyInfluxServer
HttpMode : http
Version : 1
Success : True
 
.EXAMPLE
   List-mjInfluxDB -InfluxServer NotAComputer
 
Returns:
 
Databases : {}
Server : NotAComputer
HttpMode : https
Version : 1
Success : False
 
.EXAMPLE
    List-mjInfluxDB -InfluxServer MyInfluxServer -https
 
Returns:
 
Databases : {_internal, Automatiserarse}
Server : spelburken
HttpMode : https
Version : 1
Success : True
 
#>

[cmdletbinding()]
param(
    [Parameter(Mandatory=$true)]$InfluxServer,
    [bool]$https = $false, 
    [int]$port = 8086  #
)

    begin
    {
    
        # Change to http or https.
        [string]$tmp_httpmode = (set-mjInfluxhttps -https $https)

        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ HTTP Mode ] :: $tmp_httpmode"

        # Create a Object
        $Tmp_Influxinfo          = New-InfluxDBObject
        $Tmp_Influxinfo.Server   = $InfluxServer
        $Tmp_Influxinfo.HttpMode = $tmp_httpmode

    }

    process
    {
      # Build base URL
      $tmp_posturl = "$($tmp_httpmode)://$($InfluxServer):$($port)/query?pretty=true"

      Write-Verbose "[$($MyInvocation.InvocationName)] :: [ POST URL ] :: $tmp_posturl"

      # Try to get info about Influx databases
      try{                
        $Tmp_Influxinfo.Databases = $(Invoke-RestMethod -Uri $tmp_posturl -Method Post -Body $("q=SHOW DATABASES")).results.series.values
        $Tmp_Influxinfo.Success = $true
      }
      catch{
        
        # If issues where detected try to provide help
        if ($(($Error[0].CategoryInfo).Reason) -eq "WebException")
        {
            Write-Verbose "[$($MyInvocation.InvocationName)] :: [ ERROR WebException ] :: Verify connection on specified port and protocoll"
            Write-Warning "Error connecting to $tmp_posturl"
        }
        else 
        {
            Write-Verbose "[$($MyInvocation.InvocationName)] :: [ ERROR Unknown ] :: This issue is not yet registred in my function"
            Write-Warning "This issue is new.. no info about it :("
            Write-Warning "Error connecting to $tmp_posturl"
        }

      }

    }

    end
    {
      Write-Verbose "[$($MyInvocation.InvocationName)] :: [ END ] :: returning info, found $(($Tmp_Influxinfo.Databases).count) databases"
      return $Tmp_Influxinfo
    }



}


function set-mjInfluxhttps(){
<#
.Synopsis
   change to Http or https
   written by Ispep
   www.automatiserar.se
.DESCRIPTION
   hidden function..
.EXAMPLE
   # to use https set this value to true
   set-mjInfluxhttps -https $true
 
#>

[cmdletbinding()][OutputType([String])]
param(
[Parameter(Mandatory=$true)][bool]$https = $false # unless no info is provides this is default False
)
    begin
    {
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ HTTP or HTTPS ] :: $https"
    }
    process
    {
        if ($https)
        {
           Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Selected ] :: HTTPS "
           return "https"
        } 
        else
        {
           Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Selected ] :: HTTP"
           return "http"
        }
    }

    end
    {
        
    }

}


function New-mjInfluxDB(){
<#
.Synopsis
   This function will create new InfluxDB
   Written by Ispep
   www.Automatiserar.se
.DESCRIPTION
   This function checks if an influxDB exist before writting it to the server
   if an database exist you will be promted with this warning and no database will be created:
 
    WARNING: A database with the name "Automatiserarse" exists! will not create a new one
 
.EXAMPLE
   #
   New-mjInfluxDB -databaseName "Automatiserarse" -InfluxServer MyInfluxServer
 
    Returns:
 
    Databases : {_internal, Automatiserarse}
    Success : True
    Server : MyInfluxServer
    Version : 1
    HttpMode : http
    NewDatabase : Automatiserarse
 
.EXAMPLE
   new-mjInfluxDB -databaseName "Automatiserarse" -InfluxServer MyInfluxServer -https $true -port 8086
 
    Returns:
 
    Databases : {_internal, Automatiserarse}
    Success : True
    Server : MyInfluxServer
    Version : 1
    HttpMode : http
    NewDatabase : Automatiserarse
#>

[cmdletbinding()]
param(
[Parameter(Mandatory=$true)][string]$InfluxServer,
[Parameter(Mandatory=$true)][string]$databaseName,
[int]$port = 8086,
[bool]$https
)

    begin
    {
        # Version of the script
        
        [string]$tmp_httpmode = (set-mjInfluxhttps -https $https)

        # Create an object to return.
        $tmp_NewDbObject = new-InfluxDBObject
        $tmp_NewDbObject | Add-Member -MemberType NoteProperty -Name "NewDatabase" -Value $databaseName
        $tmp_NewDbObject.Server = $InfluxServer
        $tmp_NewDbObject.HttpMode = $tmp_httpmode

        # Unless this is set to false, no database will be created
        [bool]$tmp_dbExist = $false 

        
        
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ HTTP Mode ] :: $tmp_httpmode"

        # URL to post data to
        $tmp_baseURL = "$($tmp_httpmode)://$($InfluxServer):$($port)/query"
        
        Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Base URL ] :: $tmp_baseURL"
        
    }

    process
    {
            # Check if the databases exist.
            Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Check if database exist ]"
            $tmp_currentDatabases = List-mjInfluxDB -InfluxServer $InfluxServer -https $https -port $port

            foreach ($tmp_db in $tmp_currentDatabases.Databases){
                
                Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Check if name matches] $tmp_db vs $databaseName"                
                if ($tmp_db -cmatch $databaseName){
                    
                    Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Name occupied ! ] "
                    Write-Warning "A database with the name `"$tmp_db`" exists! will not create a new one"
                    $tmp_dbExist = $true
                    break
                }
                else {
                    Write-Verbose "[$($MyInvocation.InvocationName)] :: [ No match where found ]"                     
                }
            
            
            
            }

            if (!($tmp_dbExist)){
                
                Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Create Database ] :: [ Name ] :: $databaseName"
                
                try{
                    
                    $tmp_result = Invoke-RestMethod -Method Post -Uri $tmp_baseURL -Body $("q=CREATE DATABASE $databaseName")

                    # Check if the new database is listed
                    $tmp_NewList = List-mjInfluxDB -InfluxServer $InfluxServer -https $https -port $port
                    
                    if ($($tmp_NewList.Databases.count) -gt $($tmp_currentDatabases.Databases.count)){
                        
                        $tmp_NewDbObject.Databases = $tmp_NewList.Databases
                        $tmp_NewDbObject.Success = $true
                        return $tmp_NewDbObject
                    }
                    else 
                    {
                        $tmp_NewDbObject.Databases = $tmp_NewList.Databases
                        $tmp_NewDbObject.Success = $false
                        return $tmp_NewDbObject
                    }

                }
                catch
                {
                    Write-Error "Something went wrong!"
                    break
                }
                


            }
     
                
    }

    end
    {

    }

}


function New-InfluxDBObject(){
<#
.Synopsis
   Create base objects for Influx functions
   Written by Ispep
   www.automatiserar.se
.DESCRIPTION
   This function will return a base object for all Influx functions
.EXAMPLE
   #
   New-InfluxDBObject
 
   Returns:
 
    Databases : {}
    Success : False
    Server :
    Version : 1
    HttpMode :
#>

[cmdletbinding()]
param(

)
    begin
    {
         Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Create Influx Objects ] "

         $Tmp_List_mjInfluxDBVersion = 1 # current version of the function
    }

    process
    {
            # This object is used when databases are loaded.
             Write-Verbose "[$($MyInvocation.InvocationName)] :: [ Create a database object list ] "

            $Tmp_Influxdbobject = New-Object psobject -Property ([ordered]@{
                Databases = [array]@()
                Success   = [bool]$false
                Server    = [string]""
                Version   = [int]$Tmp_List_mjInfluxDBVersion
                HttpMode  = [string]""               
            })
            
            return $Tmp_InfluxDBObject
    }

    end
    {

    }


}


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