Tag Archives


PC BattleStations | The Best Products for Cable Management

November 1, 2017 0 comments

If there is anything I hate the most it’s computer cable management.  It’s just awful even for me I’m constantly changing the way my computers setup and the layout of the room.  So i’m always adding and removing cables.  The first thing you must have is patients don’t rush your cable management or your just going to end up re-doing it again in a few weeks.

The first thing I did when I started my build was purchase my desk.  I purchased it from Ikea and wanted something to hide the cables behind it.  I needed something long because my desk consists of (2) desk’s added together.  Anyways here is everything I used for my cable management and hopefully it will help others with their computer builds.

As I come across future products and other tips for my BattleStation cable management I will be sure to update the post.  (Last updated 11/1/2017)


J Channel Cable Raceway – Black – 48″

This was a 2 pack it worked perfect because I have 2 of the same desks put together.  This came with 3M tape that was very strong it was a little longer then I needed so i took out my dremel cutter and easily cut the excess away.  If you had to or wanted to you could easily drill in the bottom of this to make sections for shorter runs.

Price:  $28.00  Order on [Amazon]

Mount-It! Dual LCD Monitor Desk Mount

When I was using dual monitors this was a must.  Recently I updated to a 34 ultra wide screen because I really didn’t need a dual monitor setup anymore.  I constantly see people running dual monitors on the stand if you want to maximize desk space and have a clean sleek build.  This will support (2) monitors up to 27″ each.

Price:  $36.99 Order on [Amazon]


Kootek 118 Inch Cable Management

Another must have product for managing your cables.

Price:  $10.99 Order on [Amazon]


Cable Clips,YOCOU 12 pcs 3-Channel

These guys saved my life a number of times.

Price:  $8.79 Order on [Amazon]


Reusable Cable Ties, Trilancer

I use these all the times rather than zip ties.

Price:  $8.99 Order on [Amazon]


Cable Management Sleeve

Another great product instead of always using zipties to minimize my exposed cables.  I came across this cable management sleeve.  It’s still sometimes  a pain because I’m always adding and removing new gadgets so I have to keep unzipping to remove/add something.  Still beats cutting zip-ties and the look is excellent!

Price:  $14.99 Order on [Amazon]

IKEA – SIGNUM Cable management

This product also helped me out, it hung down a little more then i liked it to but overall it did the trick.  I was able to mount (2) power strips on the inside then wrap all the excess cables under my desk that I did not want to be seen.  I even mounted an external hard drive, and USB 3.0 hub all inside this.

Price:  $25.99 Order on [Amazon]

Logitech Pop with Sonos & Shuffle Songs

September 23, 2017 0 comments

I’ve been using Sonos speakers for about 2 years now.  When I heard about the Logitech Pop I had to jump on board.  They are great however it lacks some features.  I have a Logitech Pop button in about every room of my house.  Some that do different things.  I.E (If i’m coming downstairs and want music playing throughout the house I can press one of my Logitech Pop buttons and do so.

If i’m doing the dishes and want music to only play in the kitchen I can press a Logitech Pop button and have music playing instantly in the kitchen.  They also have 2 other settings which is a double press, and a long press.  I have all mine configured the same so “Double Press” would skip to the next track.  “Long Press” will pause the current speaker (or all speakers).

One of my biggest downsides was every time I pressed the button to play something it would either pickup where it left off or it would start at the beginning of the list again.  I searched everywhere but I could figure out how to make the Logitech Pop button start with “Shuffle“.

I was playing around with some of the music services Sonos had to offer and I saw that Plex was now a beta option.  Since I’m a huge Plex user for all my Video, tv shows and movies.  I figured I would try adding some Music and letting Sonos stream from there.  (In the beginning it took awhile to get Sonos to actually talk to Plex I think it was something to do with the routing with Google Wifi, however not sure how but we fixed the problem).

When I added the Plex account I noticed it had a “Shuffle” all songs option.

Here are the steps for Adding Plex to your Sonos and having Logitech Pop start with “Shuffle” on press.  (Assuming you are already a Plex user).

Step 1.  Login to your Sonos app on your android device.  Click the (3 arrows at the top to display Options in Sonos).  Once there Click on “Add Music Services“.  Choose Plex.  It will ask you to login to your account.

Step 2.  Verify that Plex music service will play to one of your Sonos speakers and that “Shuffle All” is an option.

Step 3.  Launch the Logitech Pop application on your phone and update your Play buttons to (Shuffle All) from your Plex server.  Viola it was that easy.

I know it sucks if your coming from Spotify or Google Play and you have to physically store all of your Media on your server or computer.   Also if your computer or server is not running 24/7 you can now use Plex’s Cloud option.

I’m starting to love these buttons more and more they recently came out with an update that now I can control my Lutron caseta switches; Phillips Hue Bulbs and other smarthome options all with a press of a button.

SmartThings Notification through Multiple Sonos Speakers

January 12, 2017 0 comments

Since I have my Aeotec by Aeon Labs ZW056 Doorbell with SmartThings, and my custom Device Handler in SmartThings to control the doorbell.  I wanted to have a custom notification sound play through my multiple Sonos speakers.

If you need help pairing the Aeotec/Aeon labs doorbell with SmartThings visit the link below.

How I was able to pair Aeon Labs Doorbell with SmartThings


First things first you need to login to your SmartThings IDE


Next Click on “My Hubs” (this was my biggest problem at first, it wasn’t actually pulling up my devices so the Device Handler at first was never getting installed to my Hub).   If you see a message that says “You don’t have any hubs yet. Please use the SmartThings mobile app to claim your hub.”  You need to click on “My Locations“, then Click on your Hub Name mine was  called “Home“.  It should ask you to login again.  You should now see your Hub information.  Great you are now actually logged into your account.

Step 2.  Now that you are logged in we are going to be creating a new SmartThings SmartApp.  So click on My Smart Apps at the top.

Next Click on “New Smart App” in green on the top right of the page.

Next Choose “From Code“.

The following code I used thanks to SmartThings Community can be found by clicking here.

 *  Copyright 2015 SmartThings
 *  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.
 *  Sonos Custom Message
 *  Author: SmartThings
 *  Date: 2014-1-29
    name: "Sonos Notify with Sound_Multiple",
    namespace: "smartthings",
    author: "SmartThings",
    description: "Play a sound or custom message through your Sonos when the mode changes or other events occur.",
    category: "SmartThings Labs",
    iconUrl: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos.png",
    iconX2Url: "https://s3.amazonaws.com/smartapp-icons/Partner/sonos@2x.png"

preferences {
    page(name: "mainPage", title: "Play a message on your Sonos when something happens", install: true, uninstall: true)
    page(name: "chooseTrack", title: "Select a song or station")
    page(name: "timeIntervalInput", title: "Only during a certain time") {
        section {
            input "starting", "time", title: "Starting", required: false
            input "ending", "time", title: "Ending", required: false

def mainPage() {
    dynamicPage(name: "mainPage") {
        def anythingSet = anythingSet()
        if (anythingSet) {
            section("Play message when"){
                ifSet "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
                ifSet "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
                ifSet "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
                ifSet "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
                ifSet "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
                ifSet "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
                ifSet "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
                ifSet "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
                ifSet "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
                ifSet "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
                ifSet "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
                ifSet "triggerModes", "mode", title: "System Changes Mode", required: false, multiple: true
                ifSet "timeOfDay", "time", title: "At a Scheduled Time", required: false
        def hideable = anythingSet || app.installationState == "COMPLETE"
        def sectionTitle = anythingSet ? "Select additional triggers" : "Play message when..."

        section(sectionTitle, hideable: hideable, hidden: true){
            ifUnset "motion", "capability.motionSensor", title: "Motion Here", required: false, multiple: true
            ifUnset "contact", "capability.contactSensor", title: "Contact Opens", required: false, multiple: true
            ifUnset "contactClosed", "capability.contactSensor", title: "Contact Closes", required: false, multiple: true
            ifUnset "acceleration", "capability.accelerationSensor", title: "Acceleration Detected", required: false, multiple: true
            ifUnset "mySwitch", "capability.switch", title: "Switch Turned On", required: false, multiple: true
            ifUnset "mySwitchOff", "capability.switch", title: "Switch Turned Off", required: false, multiple: true
            ifUnset "arrivalPresence", "capability.presenceSensor", title: "Arrival Of", required: false, multiple: true
            ifUnset "departurePresence", "capability.presenceSensor", title: "Departure Of", required: false, multiple: true
            ifUnset "smoke", "capability.smokeDetector", title: "Smoke Detected", required: false, multiple: true
            ifUnset "water", "capability.waterSensor", title: "Water Sensor Wet", required: false, multiple: true
            ifUnset "button1", "capability.button", title: "Button Press", required:false, multiple:true //remove from production
            ifUnset "triggerModes", "mode", title: "System Changes Mode", description: "Select mode(s)", required: false, multiple: true
            ifUnset "timeOfDay", "time", title: "At a Scheduled Time", required: false
            input "actionType", "enum", title: "Action?", required: true, defaultValue: "Custom Message", options: [
                "Custom Message",
                "Bell 1",
                "Bell 2",
                "Dogs Barking",
                "Fire Alarm",
                "The mail has arrived",
                "A door opened",
                "There is motion",
                "Smartthings detected a flood",
                "Smartthings detected smoke",
                "Someone is arriving",
                "National Lampoon",
                "Leave it on the door",
                "Plain Doorbell"]
            input "message","text",title:"Play this message", required:false, multiple: false
        section {
            input "sonos", "capability.musicPlayer", title: "On this Sonos player", required: true, multiple: true
        section("More options", hideable: true, hidden: true) {
            input "resumePlaying", "bool", title: "Resume currently playing music after notification", required: false, defaultValue: true
            href "chooseTrack", title: "Or play this music or radio station", description: song ? state.selectedSong?.station : "Tap to set", state: song ? "complete" : "incomplete"

            input "volume", "number", title: "Temporarily change volume", description: "0-100%", required: false
            input "frequency", "decimal", title: "Minimum time between actions (defaults to every event)", description: "Minutes", required: false
            href "timeIntervalInput", title: "Only during a certain time", description: timeLabel ?: "Tap to set", state: timeLabel ? "complete" : "incomplete"
            input "days", "enum", title: "Only on certain days of the week", multiple: true, required: false,
                options: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
            if (settings.modes) {
                input "modes", "mode", title: "Only when mode is", multiple: true, required: false
            input "oncePerDay", "bool", title: "Only once per day", required: false, defaultValue: false
        section([mobileOnly:true]) {
            label title: "Assign a name", required: false
            mode title: "Set for specific mode(s)", required: false

def chooseTrack() {
    dynamicPage(name: "chooseTrack") {
            input "song","enum",title:"Play this track", required:true, multiple: false, options: songOptions()

private songOptions() {

    // Make sure current selection is in the set

    def options = new LinkedHashSet()
    if (state.selectedSong?.station) {
        options << state.selectedSong.station
    else if (state.selectedSong?.description) {
        // TODO - Remove eventually? 'description' for backward compatibility
        options << state.selectedSong.description

    // Query for recent tracks
    def states = sonos.statesSince("trackData", new Date(0), [max:30])
    def dataMaps = states.collect{it.jsonValue}

    log.trace "${options.size()} songs in list"
    options.take(20) as List

private saveSelectedSong() {
    try {
        def thisSong = song
        log.info "Looking for $thisSong"
        def songs = sonos.statesSince("trackData", new Date(0), [max:30]).collect{it.jsonValue}
        log.info "Searching ${songs.size()} records"

        def data = songs.find {s -> s.station == thisSong}
        log.info "Found ${data?.station}"
        if (data) {
            state.selectedSong = data
            log.debug "Selected song = $state.selectedSong"
        else if (song == state.selectedSong?.station) {
            log.debug "Selected existing entry '$song', which is no longer in the last 20 list"
        else {
            log.warn "Selected song '$song' not found"
    catch (Throwable t) {
        log.error t

private anythingSet() {
    for (name in ["motion","contact","contactClosed","acceleration","mySwitch","mySwitchOff","arrivalPresence","departurePresence","smoke","water","button1","timeOfDay","triggerModes","timeOfDay"]) {
        if (settings[name]) {
            return true
    return false

private ifUnset(Map options, String name, String capability) {
    if (!settings[name]) {
        input(options, name, capability)

private ifSet(Map options, String name, String capability) {
    if (settings[name]) {
        input(options, name, capability)

def installed() {
    log.debug "Installed with settings: ${settings}"

def updated() {
    log.debug "Updated with settings: ${settings}"

def subscribeToEvents() {
    subscribe(app, appTouchHandler)
    subscribe(contact, "contact.open", eventHandler)
    subscribe(contactClosed, "contact.closed", eventHandler)
    subscribe(acceleration, "acceleration.active", eventHandler)
    subscribe(motion, "motion.active", eventHandler)
    subscribe(mySwitch, "switch.on", eventHandler)
    subscribe(mySwitchOff, "switch.off", eventHandler)
    subscribe(arrivalPresence, "presence.present", eventHandler)
    subscribe(departurePresence, "presence.not present", eventHandler)
    subscribe(smoke, "smoke.detected", eventHandler)
    subscribe(smoke, "smoke.tested", eventHandler)
    subscribe(smoke, "carbonMonoxide.detected", eventHandler)
    subscribe(water, "water.wet", eventHandler)
    subscribe(button1, "button.pushed", eventHandler)

    if (triggerModes) {
        subscribe(location, modeChangeHandler)

    if (timeOfDay) {
        schedule(timeOfDay, scheduledTimeHandler)

    if (song) {


def eventHandler(evt) {
    log.trace "eventHandler($evt?.name: $evt?.value)"
    if (allOk) {
        log.trace "allOk"
        def lastTime = state[frequencyKey(evt)]
        if (oncePerDayOk(lastTime)) {
            if (frequency) {
                if (lastTime == null || now() - lastTime >= frequency * 60000) {
                else {
                    log.debug "Not taking action because $frequency minutes have not elapsed since last action"
            else {
        else {
            log.debug "Not taking action because it was already taken today"
def modeChangeHandler(evt) {
    log.trace "modeChangeHandler $evt.name: $evt.value ($triggerModes)"
    if (evt.value in triggerModes) {

def scheduledTimeHandler() {

def appTouchHandler(evt) {

private takeAction(evt) {

    log.trace "takeAction()"

    if (song) {
        sonos.playSoundAndTrack(state.sound.uri, state.sound.duration, state.selectedSong, volume)
    else if (resumePlaying){
        sonos.playTrackAndResume(state.sound.uri, state.sound.duration, volume)
    else {
        sonos.playTrackAndRestore(state.sound.uri, state.sound.duration, volume)

    if (frequency || oncePerDay) {
        state[frequencyKey(evt)] = now()
    log.trace "Exiting takeAction()"

private frequencyKey(evt) {

private dayString(Date date) {
    def df = new java.text.SimpleDateFormat("yyyy-MM-dd")
    if (location.timeZone) {
    else {

private oncePerDayOk(Long lastTime) {
    def result = true
    if (oncePerDay) {
        result = lastTime ? dayString(new Date()) != dayString(new Date(lastTime)) : true
        log.trace "oncePerDayOk = $result"

// TODO - centralize somehow
private getAllOk() {
    modeOk && daysOk && timeOk

private getModeOk() {
    def result = !modes || modes.contains(location.mode)
    log.trace "modeOk = $result"

private getDaysOk() {
    def result = true
    if (days) {
        def df = new java.text.SimpleDateFormat("EEEE")
        if (location.timeZone) {
        else {
        def day = df.format(new Date())
        result = days.contains(day)
    log.trace "daysOk = $result"

private getTimeOk() {
    def result = true
    if (starting && ending) {
        def currTime = now()
        def start = timeToday(starting, location?.timeZone).time
        def stop = timeToday(ending, location?.timeZone).time
        result = start < stop ? currTime >= start && currTime <= stop : currTime <= stop || currTime >= start
    log.trace "timeOk = $result"

private hhmm(time, fmt = "h:mm a")
    def t = timeToday(time, location.timeZone)
    def f = new java.text.SimpleDateFormat(fmt)
    f.setTimeZone(location.timeZone ?: timeZone(time))

private getTimeLabel()
    (starting && ending) ? hhmm(starting) + "-" + hhmm(ending, "h:mm a z") : ""
// TODO - End Centralize

private loadText() {
    switch ( actionType) {
        case "Bell 1":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/bell1.mp3", duration: "10"]
        case "Bell 2":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/bell2.mp3", duration: "10"]
        case "Dogs Barking":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/dogs.mp3", duration: "10"]
        case "Fire Alarm":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/alarm.mp3", duration: "17"]
        case "The mail has arrived":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/the+mail+has+arrived.mp3", duration: "1"]
        case "A door opened":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/a+door+opened.mp3", duration: "1"]
        case "There is motion":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/there+is+motion.mp3", duration: "1"]
        case "Smartthings detected a flood":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/smartthings+detected+a+flood.mp3", duration: "2"]
        case "Smartthings detected smoke":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/smartthings+detected+smoke.mp3", duration: "1"]
        case "Someone is arriving":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/someone+is+arriving.mp3", duration: "1"]
        case "Piano":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/piano2.mp3", duration: "10"]
        case "Lightsaber":
            state.sound = [uri: "http://s3.amazonaws.com/smartapp-media/sonos/lightsaber.mp3", duration: "10"]
            case "National Lampoon":
            state.sound = [uri: "http://l5j.net/sounds/nationallampoon.mp3", duration: "27"]
            case "Leave it on the door":
            state.sound = [uri: "http://l5j.net/sounds/leaveitonthedoor.mp3", duration: "8"]
             case "Plain Doorbell":
            state.sound = [uri: "http://l5j.net/sounds/doorbell.mp3", duration: "11"]
            if (message) {
                state.sound = textToSpeech(message instanceof List ? message[0] : message) // not sure why this is (sometimes) needed)
            else {
                state.sound = textToSpeech("You selected the custom message option but did not enter a message in the $app.label Smart App")

Once your code has been pasted Choose “Save“, then “Publish“.

Next Open up your SmartThings application on your android or iPhone.

Click on “Add a SmartApp” at the bottom.

Next all the way down and choose “My Apps” since this was a custom App that we added.

You should now see your Sonos Notify with Sound_Multiple.  This will allow you to choose multiple Sonos speakers for your Doorbell notifications.

Here’s how I set up my doorbell.  I made sure on the Doorbell Button Press (Aeotec Doorbell) was triggered it would play the custom .mp3 that I have added.  ( I will explain in my next post on how to add your own custom sounds to the list).   If you used my code from the top you will notice I added the “National Lampoons Christmas Vacation Doorbell“.  It’s also set to play throughout my Sonos speakers.

Here’s some more settings you can also set.  I wanted to make sure if I was playing music and someone rang the doorbell, the music would continue playing.

Also I wanted to temporarily change the music volume so I could hear the doorbell notification sound.