/* * HyperCube * * Description: * This Hubitat driver polls and allows for basic control of a HyperCube. Relies on the WLED implementation used by HyperCubes * and is thus fairly adaptable for other WLED-based devices. * * Link to Hyperspace Lighting company: * https://hyperspacelight.com/ * Link to WLED Json API: * https://kno.wled.ge/interfaces/json-api/ * * Features List: * Poll the HyperCube for status information * Basic on/off control via switch * Basic brightness/level controls * Set the effect based on effect # (sorry, there are an awful lot so getting them added as names would be tough) * Set the palette based on #/name (only 27 of these) * Ability to "freeze" and "unfreeze" what is currently displayed * Polls drdsnell.com daily to check for updated drivers * * Instructions for using Tile Template method (originally based on @mircolino's HTML Templates): * 1) In "Hubitat -> Devices" select the child/sensor (not the parent) you would like to "templetize" * 2) In "Preferences -> Tile Template" enter your template (example below) and click "Save Preferences" * Ex: "[b]Effect:[/b] ${ EffectName }[/br]" * 3) In a Hubitat dashboard, add a new tile, and select the child/sensor, in the center select "Attribute", and on the right select the "Tile" attribute * 4) Select the Add Tile button and the tile should appear * NOTE: Should accept most HTML formatting commands with [] instead of <> * * Licensing: * Copyright 2024 David Snell * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at: http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License * for the specific language governing permissions and limitations under the License. * * Version Control: * 0.1.4 - Correction to ProcessEvent function and removal of old driver-specific attributes when Preferences are saved * 0.1.3 - Checking for repeated connection failures and disabling refresh until preferences are saved again or refresh is run manually * 0.1.2 - Fix for initial null state of Effects and Palettes * 0.1.1 - Changes to handle null data responses for palettes and effects, added control over palettes * 0.1.0 - Initial version * * Thank you(s): * @Cobra's contributions to the community, the driver update notice is based on his original method * @mircolino for working out the HTML Template method for dashboard use */ // Returns the driver name def DriverName(){ return "HyperCube" } // Returns the driver version def DriverVersion(){ return "0.1.4" } metadata{ definition ( name: "HyperCube", namespace: "Snell", author: "David Snell", importUrl: "https://www.drdsnell.com/projects/hubitat/drivers/HyperCube.groovy" ) { // Attempting to indicate what capabilities the device should be capable of capability "Sensor" capability "Refresh" capability "Switch" capability "SwitchLevel" capability "LightEffects" capability "Actuator" // Commands //command "DoSomething" // Test command that should be commented out before publishing command "Freeze" // Freeze the current HyperCube LEDs command "UnFreeze" // UnFreeze the current HyperCube LEDs command "SetBrightness", [ [ name: "Brightness", type: "INTEGER", constraints: [ 0 .. 255 ], description: "Enter Brightness (ex: 0 to 255)" ] ] // Set the HyperCube's brightness /* command "SetDuration", [ [ name: "Duration", type: "INTEGER", constraints: [ 0 .. 255 ], description: "Enter Duration (ex: 0 to 255) in 1/10 seconds" ] ] // Set the HyperCube's transition duration, no idea what it does yet */ command "GetInfo" command "CheckEffects" command "CheckPalettes" command "SetMode", [ [ name: "Mode", type: "ENUM", constraints: [ "Kaleidoscopic", "Meditative", "Sound Reactive" ], description: "Select the mode." ], ] // Set the overall mode of the HyperCube command "SetNightlight", [ [ name: "Mode", type: "ENUM", constraints: [ "on", "off" ], description: "Set nightlight on or off." ], ] // Set the nightlight for HyperCube command "SetPalette", [ [ name: "Palette", type: "ENUM", constraints: [ "0 : Default", "1 : Custom", "2 : Aurora", "3 : Aurora II", "4 : C9", "5 : Chromatic", "6 : Chromatic II", "7 : Forest", "8 : Green Giant", "9 : Harmonious", "10 : Kaleidoscope I", "11 : Kaleidoscope II", "12 : Lava", "13 : Luminous", "14 : Molten Sea", "15 : Nebula", "16 : Neptune", "17 : Ocean", "18 : Pastel", "19 : Red Titan", "20 : Solar Skys", "21 : Spectral", "22 : Stellar Flare", "23 : Sunset", "24 : Tiamat", "25 : Ultraviolet", "26 : Yelblu" ], description: "Select the palette." ], ] // Set the current palette of the HyperCube /* command "SetNightlightBrightness", [ [ name: "Brightness", type: "INTEGER", constraints: [ 0 .. 255 ], description: "Enter Brightness (ex: 0 to 255)" ] ] // Set the HyperCube's nightlight brightness command "SetNightlightDuration", [ [ name: "Duration", type: "INTEGER", constraints: [ 0 .. 255 ], description: "Enter Duration (ex: 0 to 255) in minutes" ] ] // Set the HyperCube's nightlight duration */ // Attributes for the driver attribute "DriverName", "string" // Driver identifies the driver being used for update purposes attribute "DriverVersion", "string" // Version number of the driver attribute "DriverStatus", "string" // Status of the driver version compared to what is currently published // Attributes for the device itself attribute "Brightness", "number" // Brightness of the overall device from 0 to 255 attribute "Effect_ID", "number" // Tracks the ID# of the current mode/light effect in use attribute "EffectName", "string" // Name of the Light Effect currently in use attribute "Palette_ID", "number" // Tracks the ID# of the current palette in use attribute "PaletteName", "string" // The name of the current palette in use attribute "CurrentlyShowing", "string" // An attempt to tell what is currently being displayed attribute "Crossfade_Duration", "number" // Transition value for crossfade duration in ms (transition returned is 0 to 255 * 100 for ms per API) attribute "Nightlight", "enum", [ "on", "off" ] // Whether the nightlight mode is activated or not attribute "Nightlight_Duration", "number" // Nightlight duration in minutes from 0 to 255 //attribute "Nightlight_Brightness", "number" // Brightness of the nightlight from 0 to 255 attribute "Uptime", "string" // Total uptime since device was last booted/reset attribute "Status", "string" // General device status // States used for information in the driver (for reference purposes, styled like attributes) // "ConnectionFailures", "number" // Total failures in a row // Tile Template attribute attribute "Tile", "string"; // Ex: "[b]Light Effect:[/b] ${ Light_Effect }[/br]" } preferences{ section{ input( type: "enum", name: "RefreshRate", title: "Refresh Rate", required: false, multiple: false, options: [ "1 minute", "5 minutes", "10 minutes", "15 minutes", "30 minutes", "1 hour", "3 hours", "Manual" ], defaultValue: "5 minutes" ) input( type: "string", name: "NetworkAddress", title: "HyperCube IP/Hostname", required: true ) input( type: "string", name: "TileTemplate", title: "Tile Template", description: "Ex: [b]Effect:[/b] \${ EffectName }[/br]", defaultValue: "" ) input( type: "enum", name: "LogType", title: "Enable Logging?", required: true, multiple: false, options: [ "None", "Info", "Debug", "Trace" ], defaultValue: "Info" ) } } } //DoSomething is a test command that should be commented out before publishing def DoSomething(){ } // updated is called whenever device parameters are saved // It sets the current version of the driver and sets some basic settings def updated(){ Logging( "Updated", 2 ) // Set the driver name and version before update checking is scheduled if( state."Driver Name" != null ){ state.remove( "Driver Name" ) state.remove( "Driver Version" ) device.deleteCurrentState( "Driver Name" ) device.deleteCurrentState( "Driver Version" ) } ProcessState( "DriverName", "${ DriverName() }" ) ProcessState( "DriverVersion", "${ DriverVersion() }" ) ProcessState( "ConnectionFailures", 0 ) unschedule() if( NetworkAddress != null ){ // Check what the refresh rate is set for then run it switch( RefreshRate ){ case "1 minute": runEvery1Minute( "refresh" ) break case "5 minutes": runEvery5Minutes( "refresh" ) break case "10 minutes": runEvery10Minutes( "refresh" ) break case "15 minutes": runEvery15Minutes( "refresh" ) break case "30 minutes": runEvery30Minutes( "refresh" ) break case "1 hour": runEvery1Hour( "refresh" ) break case "3 hours": runEvery3Hours( "refresh" ) break case "Manual": unschedule( "refresh" ) break } Logging( "Refresh rate: ${ RefreshRate }", 3 ) schedule( new Date(), DailyCheck ) } } // Performs checks that do not need to be done on every refresh def DailyCheck(){ CheckEffects() pauseExecution( 2000 ) CheckPalettes() pauseExecution( 2000 ) GetInfo() pauseExecution( 2000 ) refresh() pauseExecution( 2000 ) CheckForUpdate() } // refresh polls for data def refresh(){ def Params = null Params = [ uri: "http://${ NetworkAddress }/json/state", contentType: "application/json" ] asynchttpGet( "ReceiveData", Params, [ Method: "refresh" ] ) } // GetInfo queries the device for any general device information def GetInfo(){ def Params = null Params = [ uri: "http://${ NetworkAddress }/json/info", contentType: "application/json" ] asynchttpGet( "ReceiveData", Params, [ Method: "GetInfo" ] ) } // CheckEffects queries the device for any stored effects def CheckEffects(){ def Params = null Params = [ uri: "http://${ NetworkAddress }/json/effects", contentType: "application/json" ] asynchttpGet( "ReceiveData", Params, [ Method: "CheckEffects" ] ) } // CheckPalettes queries the device for any stored effects def CheckPalettes(){ def Params = null Params = [ uri: "http://${ NetworkAddress }/json/palettes", contentType: "application/json" ] asynchttpGet( "ReceiveData", Params, [ Method: "CheckPalettes" ] ) } // Handles the responses def ReceiveData( resp, data ){ if( resp.getStatus() == 200 ){ if( state.ConnectionFailures >= 5 ){ // Check what the refresh rate is set for then run it switch( RefreshRate ){ case "1 minute": runEvery1Minute( "refresh" ) break case "5 minutes": runEvery5Minutes( "refresh" ) break case "10 minutes": runEvery10Minutes( "refresh" ) break case "15 minutes": runEvery15Minutes( "refresh" ) break case "30 minutes": runEvery30Minutes( "refresh" ) break case "1 hour": runEvery1Hour( "refresh" ) break case "3 hours": runEvery3Hours( "refresh" ) break case "Manual": unschedule( "refresh" ) break } Logging( "Refresh rate restarted after connection success: ${ RefreshRate }", 3 ) } ProcessState( "ConnectionFailures", 0 ) ProcessEvent( "Status", "${ data.Method } succeeded @ ${ new Date() }" ) switch( data.Method ){ case "CheckEffects": Logging( "CheckEffects Response = ${ resp.data }", 4 ) def Temp = resp.data.replaceAll( "\"", "" ) Temp = Temp.split( "," ) Temp[ 0 ] = Temp[ 0 ].split( "\\[" )[ 1 ] Temp[ ( Temp.size() - 1 ) ] = Temp[ ( Temp.size() - 1 ) ].split( "\\]" )[ 0 ] ProcessState( "Effects", Temp ) break case "CheckPalettes": Logging( "CheckPalettes Response = ${ resp.data }", 4 ) def Temp = resp.data.replaceAll( "\"", "" ) Temp = Temp.split( "," ) Temp[ 0 ] = Temp[ 0 ].split( "\\[" )[ 1 ] Temp[ ( Temp.size() - 1 ) ] = Temp[ ( Temp.size() - 1 ) ].split( "\\]" )[ 0 ] ProcessState( "Palettes", Temp ) break case "GetInfo": Logging( "GetInfo Response = ${ resp.data }", 4 ) def Data = parseJson( resp.data ) Data.each(){ switch( it.key ){ case "ver": ProcessState( "Device_Firmware", it.value ) break case "leds": if( it.value.count != null ){ ProcessState( "LED_Count", it.value.count as int ) } if( it.value.rgbw ){ ProcessState( "LED_Type", "RGBW" ) } else { ProcessState( "LED_Type", "RGB" ) } break case "name": if( ( it.value != null ) && ( device.getLabel() == null ) ){ device.setLabel( it.value ) } break case "arch": if( it.value != null ){ ProcessState( "Platform", it.value ) } break case "product": if( it.value != null ){ ProcessState( "Product", it.value ) } break case "mac": if( it.value != null ){ ProcessState( "MAC", it.value ) } break case "uptime": if( it.value > 0 ){ def TempUptime = it.value as int def TempUptimeDays = Math.round( TempUptime / 86400 ) def TempUptimeHours = Math.round( ( TempUptime % 86400 ) / 3600 ) def TempUptimeMinutes = Math.round( ( TempUptime % 3600 ) / 60 ) def TempUptimeString = "" if( TempUptimeDays > 0 ){ TempUptimeString = "${ TempUptimeDays } Day" } if( TempUptimeDays >= 1 ){ TempUptimeString += "s" } if( TempUptimeHours > 0 ){ TempUptimeString += " ${ TempUptimeHours } Hour" } if( TempUptimeHours >= 1 ){ TempUptimeString += "s" } if( TempUptimeMinutes > 0 ){ TempUptimeString += " ${ TempUptimeMinutes } Minute" } if( TempUptimeMinutes >= 1 ){ TempUptimeString += "s" } ProcessEvent( "Uptime", TempUptimeString ) } break } } break case "Command": case "refresh": Logging( "refresh/Command Response = ${ resp.data }", 4 ) Json = parseJson( resp.data ) Json.each{ switch( it.key ){ case "on": if( it.value ){ ProcessEvent( "switch", "on" ) } else { ProcessEvent( "switch", "off" ) } break case "bri": ProcessEvent( "Brightness", it.value ) break case "nl": if( it.value.on ){ ProcessEvent( "Nightlight", "on" ) } else { ProcessEvent( "Nightlight", "off" ) } ProcessEvent( "Nightlight_Duration", it.value.dur, "minutes" ) // NOTE: Nightlight Fade was removed in WLED 0.13.0 and replaced as a function of Nightlight Mode //ProcessEvent( "Nightlight_Brightness", it.value.tbri ) // Removed as it does not appear to actually relate to how bright nightlight is break case "transition": ProcessEvent( "Crossfade_Duration", it.value as int ) break case "seg": def EffectChange = "false" def PaletteChange = "false" if( ( it.value[ 0 ].fx != null ) && ( it.value[ 0 ].fx != state.Effect_ID ) ){ ProcessEvent( "Effect_ID", it.value[ 0 ].fx ) EffectChange = "true" if( it.value[ 0 ].fx >= 0 ){ ProcessEvent( "EffectName", "${ state.Effects[ it.value[ 0 ].fx ] }" ) } else { ProcessEvent( "EffectName", "${ state.Effects[ 0 ] }" ) } } if( it.value[ 0 ].pal != null && ( it.value[ 0 ].pal != state.Palette_ID ) ){ PaletteChange = "true" ProcessEvent( "Palette_ID", it.value[ 0 ].pal ) if( state.Palettes != null ){ ProcessEvent( "PaletteName", state.Palettes[ it.value[ 0 ].pal ] ) } } if( ( EffectChange == "true" ) && ( PaletteChange == "false" ) ){ ProcessEvent( "CurrentlyShowing", "Effect: ${ state.Effects[ it.value[ 0 ].fx ] }" ) } else if( ( EffectChange == "false" ) && ( PaletteChange == "true" ) ){ ProcessEvent( "CurrentlyShowing", "Palette: ${ state.Palettes[ it.value[ 0 ].pal ] }" ) } break case "ps": ProcessState( "PresetID", it.value ) break case "pl": ProcessState( "PlaylistID", it.value ) break case "udpn": if( it.value.send ){ ProcessState( "UDP_Send", "true" ) } else { ProcessState( "UDP_Send", "false" ) } if( it.value.recv ){ ProcessState( "UDP_Receive", "true" ) } else { ProcessState( "UDP_Receive", "false" ) } break // Data to ignore case "pss": // Removed as of WLED 0.11.1 case "fb": // Sent in state data but not in WLED API (appears to be an integer) case "sb": // Sent in state data but not in WLED API (appears to be true/false value) break default: Logging( "Unhandled data: ${ it.key } = ${ it.value }", 3 ) break } } break } } else { Logging( "Error connecting: ${ resp.status }", 5 ) ProcessState( "ConnectionFailures", ( state.ConnectionFailures + 1 ) ) if( ConnectionFailures >= 5 ){ Logging( "Too many connection failures ( ${ state.ConnectionFailures } ) so cancelling refresh and setting warning.", 5 ) unschedule( "refresh" ) ProcessEvent( "Status", "Repeated Connection Failures, check device's network connection." ) } } } // Turn HyperCube off def off(){ PostCommand( "{\"on\":false,\"v\":true}", "Off" ) } // Turn HyperCube on def on(){ PostCommand( "{\"on\":true,\"v\":true}", "On" ) } // Freeze current HyperCube LEDs def Freeze(){ PostCommand( "{\"seg\":[{\"psd\":true}],\"v\":true}", "Freeze" ) } // UnFreeze current HyperCube LEDs def UnFreeze(){ PostCommand( "{\"seg\":[{\"psd\":false}],\"v\":true}", "Unfreeze" ) } // Set the HyperCube effect def setEffect( Number Value ){ PostCommand( "{\"seg\":[{\"fx\":${ Value as int }}],\"v\":true}", "SetEffect" ) } // Set to next HyperCube effect def setNextEffect(){ if( state.Effect_ID != null ){ def TempNumber = ( state.Effect_ID + 1 ) if( TempNumber < state.Effects.size() ){ setEffect( TempNumber ) } else { setEffect( 0 ) } } else { setEffect( 0 ) } } // Set to previous HyperCube effect def setPreviousEffect(){ if( state.Effect_ID != null ){ def TempNumber = ( state.Effect_ID - 1 ) if( TempNumber >= 0 ){ setEffect( TempNumber ) } else { setEffect( state.Effects.size() ) } } else { setEffect( 0 ) } } // Set the HyperCube nightlight mode def SetNightlight( String Mode ){ def Temp = "true" if( Mode == "off" ){ Temp = "false" } PostCommand( "{\"nl\":{\"on\":${ Temp }},\"v\":true}", "SetNightlight" ) } // Set the HyperCube nightlight brightness def SetNightlightBrightness( Value ){ def Temp = "true" if( state.Nightlight == "off" ){ Temp = "false" } PostCommand( "{\"nl\":[{\"on\":${ Temp },\"dur\":${ state.Nightlight_Duration },\"tbri\":${ Value }}],\"v\":true}", "SetNightlightBrightness" ) } // Set the HyperCube nightlight Duration def SetNightlightDuration( Value ){ def Temp = "true" if( state.Nightlight == "off" ){ Temp = "false" } PostCommand( "{\"nl\":[{\"on\":${ Temp },\"dur\":${ Value },\"tbri\":${ state.Nightlight_Brightness }}],\"v\":true}", "SetNightlightDuration" ) } // Set the overall HyperCube mode def SetMode( String Mode ){ switch( Mode ){ case "Kaleidoscopic": PostCommand( "{\"seg\":[{\"fx\":0}],\"v\":true}", "SetMode Kaleidoscopic" ) break case "Meditative": PostCommand( "{\"seg\":[{\"fx\":1}],\"v\":true}", "SetMode Meditative" ) break case "Sound Reactive": PostCommand( "{\"seg\":[{\"fx\":2}],\"v\":true}", "SetMode Sound Reactive" ) break } } // Set the overall HyperCube palette def SetPalette( Palette ){ def TempSplit = Palette.split( " : " ) PostCommand( "{\"seg\":[{\"pal\":${ TempSplit[ 0 ] as int }}],\"v\":true}", "SetPalette" ) } // Set HyperCube brightness by level % def setLevel( Value ){ SetBrightness( ( Value * 2.55 ) as int ) } // Set HyperCube brightness def SetBrightness( Value ){ PostCommand( "{\"bri\":${ Value as int },\"v\":true}", "SetBrightness" ) } // Set HyperCube crossfade duration def SetDuration( Value ){ PostCommand( "{\"transition\":${ Value as int },\"v\":true}", "SetDuration" ) } // Send command def PostCommand( Command, CommandName = null ){ Logging( "Attempting to post command ${ CommandName } to HyperCube", 4 ) def Params = null Params = [ uri: "http://${ NetworkAddress }/json/state", contentType: "application/json", body: "${ Command }" ] asynchttpPost( "ReceiveData", Params, [ Method: "Command: ${ CommandName }" ] ) } // Tile Template method based on @mircolino's HTML Template method private void UpdateTile( Variable = null, Value = null ){ if( settings.TileTemplate ){ def val = settings.TileTemplate.toString().replaceAll( "\\[", "<" ) val = val.replaceAll( "\\]", ">" ) val = val.replaceAll( ~/\$\{\s*([A-Za-z][A-Za-z0-9_]*)\s*\}/ ){ java.util.ArrayList m -> state."${ m [ 1 ] }" } if( state.Tile != val ){ sendEvent( name: "Tile", value: val, isStateChanged: true ) state.Tile = val } } } // Process data to check against current state value and then send an event if it has changed def ProcessEvent( Variable, Value, Unit = null, ForceEvent = false ){ if( ( state."${ Variable }" != Value ) || ( ForceEvent == true ) ){ state."${ Variable }" = Value if( Unit != null ){ Logging( "Event: ${ Variable } = ${ Value }${ Unit }", 4 ) sendEvent( name: "${ Variable }", value: Value, unit: Unit, isStateChange: true ) } else { Logging( "Event: ${ Variable } = ${ Value }", 4 ) sendEvent( name: "${ Variable }", value: Value, isStateChange: true ) } UpdateTile() } } // Process data to check against current state value and update if it has changed def ProcessState( Variable, Value ){ if( state."${ Variable }" != Value ){ Logging( "State: ${ Variable } = ${ Value }", 4 ) state."${ Variable }" = Value UpdateTile() } } // installed is called when the device is installed, all it really does is run updated def installed(){ Logging( "Installed", 2 ) updated() } // Handles whether logging is enabled and thus what to put there. def Logging( LogMessage, LogLevel ){ // Add all messages as info logging if( ( LogLevel == 2 ) && ( LogType != "None" ) ){ log.info( "${ device.displayName } - ${ LogMessage }" ) } else if( ( LogLevel == 3 ) && ( ( LogType == "Debug" ) || ( LogType == "Trace" ) ) ){ log.debug( "${ device.displayName } - ${ LogMessage }" ) } else if( ( LogLevel == 4 ) && ( LogType == "Trace" ) ){ log.trace( "${ device.displayName } - ${ LogMessage }" ) } else if( LogLevel == 5 ){ log.error( "${ device.displayName } - ${ LogMessage }" ) } } // Checks drdsnell.com for the latest version of the driver // Original inspiration from @cobra's version checking def CheckForUpdate(){ ProcessEvent( "DriverName", DriverName() ) ProcessEvent( "DriverVersion", DriverVersion() ) httpGet( uri: "https://www.drdsnell.com/projects/hubitat/drivers/versions.json", contentType: "application/json" ){ resp -> switch( resp.status ){ case 200: if( resp.data."${ DriverName() }" ){ CurrentVersion = DriverVersion().split( /\./ ) if( resp.data."${ DriverName() }".version == "REPLACED" ){ ProcessEvent( "DriverStatus", "Driver replaced, please use ${ resp.data."${ state.DriverName }".file }" ) } else if( resp.data."${ DriverName() }".version == "REMOVED" ){ ProcessEvent( "DriverStatus", "Driver removed and no longer supported." ) } else { SiteVersion = resp.data."${ DriverName() }".version.split( /\./ ) if( CurrentVersion == SiteVersion ){ Logging( "Driver version up to date", 3 ) ProcessEvent( "DriverStatus", "Up to date" ) } else if( ( CurrentVersion[ 0 ] as int ) > ( SiteVersion [ 0 ] as int ) ){ Logging( "Major development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 ) ProcessEvent( "DriverStatus", "Major development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" ) } else if( ( CurrentVersion[ 1 ] as int ) > ( SiteVersion [ 1 ] as int ) ){ Logging( "Minor development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 ) ProcessEvent( "DriverStatus", "Minor development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" ) } else if( ( CurrentVersion[ 2 ] as int ) > ( SiteVersion [ 2 ] as int ) ){ Logging( "Patch development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version", 3 ) ProcessEvent( "DriverStatus", "Patch development ${ CurrentVersion[ 0 ] }.${ CurrentVersion[ 1 ] }.${ CurrentVersion[ 2 ] } version" ) } else if( ( SiteVersion[ 0 ] as int ) > ( CurrentVersion[ 0 ] as int ) ){ Logging( "New major release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 ) ProcessEvent( "DriverStatus", "New major release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" ) } else if( ( SiteVersion[ 1 ] as int ) > ( CurrentVersion[ 1 ] as int ) ){ Logging( "New minor release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 ) ProcessEvent( "DriverStatus", "New minor release ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" ) } else if( ( SiteVersion[ 2 ] as int ) > ( CurrentVersion[ 2 ] as int ) ){ Logging( "New patch ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available", 2 ) ProcessEvent( "DriverStatus", "New patch ${ SiteVersion[ 0 ] }.${ SiteVersion[ 1 ] }.${ SiteVersion[ 2 ] } available" ) } } } else { Logging( "${ DriverName() } is not published on drdsnell.com", 2 ) ProcessEvent( "DriverStatus", "${ DriverName() } is not published on drdsnell.com" ) } break default: Logging( "Unable to check drdsnell.com for ${ DriverName() } driver updates.", 2 ) break } } }