[RELEASE] Watchtower long-term metrics app

Looks nice. Good work.

1 Like

Released version 1.1.0 with the following small change:

Added

  • Add option to set charts y-axis scale to "auto" or "fixed" - @marktheknife
Screenshot

watchtower_1.1.0

This option is saved per dashboard and affects all charts that it contains. The default value is now "auto".

Have fun!

5 Likes

@dandanache,
I have added light/switch or dimmer, but for some reason there is a negative value, is it possible to fix this (see bathroom light 1 below)?
Thanks again

Summary

1 Like

Doing this at the airport on my phone, so maybe that's the problem, but I can't get the sidebar clothes so I can see the screen behind it. Tapping on the screen behind it doesn't work and also just changing the settings doesn't make it go away.

1 Like

I think it is. I couldn’t get anything going on the dashboard while using my iPhone when I first installed the app, but the dashboard seems to work as expected on a desktop browser.

3 Likes

You need to drag/swipe it to the left to make it go away. To bring it back on, just swipe right from the edge of the screen.

But currently you cannot add/move/zoom widgets on mobile. View-only so far.

2 Likes

I swear I tried that, I must not have giving it a vigorous enough swipe. Thanks for the tip, I'll wait till I get home to play more with this new toy!

1 Like

Swipes must start (when opening) or end (when closing) very close the left edge, otherwise it won't register :slight_smile:

Actually, swiping the menu on and off is the most exciting thing you can do on a mobile phone with a new dashboard. It is also the only thing you can do :slight_smile:

2 Likes

This is weird, I cannot reproduce it. Can you please look into that specific csv data file (Watchtower/Devices/click device/click data file) and see if there is a negative value in there? Otherwise it is a UI/graph rendering bug.

Yes, there is a negative value @12.40pm: Switch -11% on (all zero values filtered out):

1 Like

I really like the idea and promise of this app, so I installed it on one of my 2 Hubitat hubs. It seems to work fine there, but on the other hub it does not collect data for any of the 2 devices I configure.

I turned on logging and got this error message:

java.lang.NullPointerException: null on line 124 (method collectDeviceMetrics)

Does that give a clue on the error?

1 Like

This has been fixed, use the "Repair" function in HPM to re-download the updated file(s) from GitHub.

1 Like

Great, worked like a charm. Puzzled why this only happened on one of the hubs, but thanks for the heads-up :slight_smile:

1 Like

Curious about the limited attribute choice.

There are 53 attributes available for this weather device'

1 Like

How many are type 'NUMBER'?

1 Like

Most, wind speed, daily rainfall, weekly rainfall, barometer, dew point, etc, objective weather data.

1 Like

What driver is that?

1 Like

From Ambient weather station app. Kurt Sanders

2 Likes

If I grabbed the right source it looks like 22 of the attributes are listed as type number, so that's not the criteria. Guess I'll poke around in the code to see what's he's using.

Edit: Found it. He has a list of standard attributes that he's looking for. He may entertain adding some more if you ask.

Attribute List
@Field static final Map SUPPORTED_ATTRIBUTES = [
    hubCPU: [ min:0, max:100, unit:'%', probe:{ state -> state.hubCPU ?: '0' } ],
    hubRAM: [ min:0, unit:'MB', probe:{ state -> state.hubRAM ?: '0' } ],
    hubTemperature: [ min:0, unit:'°', probe:{ state -> state.hubTemperature ?: '0' } ],
    hubDatabaseSize: [ min:0, unit:'MB', probe:{ state -> state.hubDatabaseSize ?: '0' } ],

    acceleration: [ min:0, max:100, unit:'% active', probe:{ device -> "${device.currentValue('acceleration')}" == 'active' ? 100 : 0 } ],
    airQualityIndex: [ min:0, max:500, unit:'', probe:{ device -> "${device.currentValue('airQualityIndex')}" } ],
    amperage: [ min:0, unit:'A', probe:{ device -> "${device.currentValue('amperage')}" } ],
    battery: [ min:0, max:100, unit:'%', probe:{ device -> "${device.currentValue('battery')}" } ],
    camera: [ min:0, max:100, unit:'% on', probe:{ device -> "${device.currentValue('camera')}" == 'on' ? 100 : 0 } ],
    carbonDioxide: [ min:0, unit:'ppm', probe:{ device -> "${device.currentValue('carbonDioxide')}" } ],
    contact: [ min:0, max:100, unit:'% open', probe:{ device -> "${device.currentValue('contact')}" == 'open' ? 100 : 0 } ],
    coolingSetpoint: [ min:0, unit:'°', probe:{ device -> "${device.currentValue('coolingSetpoint')}" } ],
    door: [ min:0, max:100, unit:'% open', probe:{ device -> "${device.currentValue('door')}" == 'open' ? 100 : 0 } ],
    energy: [ min:0, unit:'kWh', probe:{ device -> "${device.currentValue('energy')}" } ],
    filterStatus: [ min:0, max:100, unit:'% normal', probe:{ device -> "${device.currentValue('filterStatus')}" == 'normal' ? 100 : 0 } ],
    frequency: [ unit:'Hz', probe:{ device -> "${device.currentValue('frequency')}" } ],
    goal: [ min:0, unit:'steps', probe:{ device -> "${device.currentValue('goal')}" } ],
    heatingSetpoint: [ min:0, unit:'°', probe:{ device -> "${device.currentValue('heatingSetpoint')}" } ],
    humidity: [ min:0, max:100, unit:'%', probe:{ device -> "${device.currentValue('humidity')}" } ],
    illuminance: [ min:0, unit:'lx', probe:{ device -> "${device.currentValue('illuminance')}" } ],
    lock: [ unit:'% locked', probe:{ device -> "${device.currentValue('lock')}" == 'locked' ? 100 : 0 } ],
    lqi: [ min:0, max:255, unit:'lqi', probe:{ device -> "${device.currentValue('lqi')}" } ],
    motion: [ min:0, max:100, unit:'% active', probe:{ device -> "${device.currentValue('motion')}" == 'active' ? 100 : 0 } ],
    naturalGas: [ min:0, max:100, unit:'% detected', probe:{ device -> "${device.currentValue('naturalGas')}" == 'detected' ? 100 : 0 } ],
    networkStatus: [ min:0, max:100, unit:'% online', probe:{ device -> "${device.currentValue('networkStatus')}" == 'online' ? 100 : 0 } ],
    pH: [ unit:'pH', probe:{ device -> "${device.currentValue('pH')}" } ],
    power: [ min:0, unit:'W', probe:{ device -> "${device.currentValue('power')}" } ],
    presence: [ min:0, max:100, unit:'% present', probe:{ device -> "${device.currentValue('presence')}" == 'present' ? 100 : 0 } ],
    pressure: [ min:0, unit:'psi', probe:{ device -> "${device.currentValue('pressure')}" } ],
    rate: [ min:0, unit:'LPM', probe:{ device -> "${device.currentValue('rate')}" } ],
    rssi: [ min:0, max:255, unit:'rssi', probe:{ device -> "${device.currentValue('rssi')}" } ],
    securityKeypad: [ min:0, max:100, unit:'% armed', probe:{ device -> "${device.currentValue('securityKeypad')}".startsWith('armed') ? 100 : 0 } ],
    sessionStatus: [ min:0, max:100, unit:'% running', probe:{ device -> "${device.currentValue('sessionStatus')}" == 'running' ? 100 : 0 } ],
    shock: [ min:0, max:100, unit:'% detected', probe:{ device -> "${device.currentValue('shock')}" == 'detected' ? 100 : 0 } ],
    sleeping: [ min:0, max:100, unit:'% sleeping', probe:{ device -> "${device.currentValue('sleeping')}" == 'sleeping' ? 100 : 0 } ],
    smoke: [ min:0, max:100, unit:'% detected', probe:{ device -> "${device.currentValue('smoke')}" == 'detected' ? 100 : 0 } ],
    sound: [ min:0, max:100, unit:'% detected', probe:{ device -> "${device.currentValue('sound')}" == 'detected' ? 100 : 0 } ],
    soundPressureLevel: [ unit:'dB', probe:{ device -> "${device.currentValue('soundPressureLevel')}" } ],
    steps: [ unit:'steps', probe:{ device -> "${device.currentValue('steps')}" } ],
    'switch': [ min:0, max:100, unit:'% on', probe:{ device -> "${device.currentValue('switch')}" == 'on' ? 100 : 0 } ],
    tamper: [ min:0, max:100, unit:'% detected', probe:{ device -> "${device.currentValue('tamper')}" == 'detected' ? 100 : 0 } ],
    temperature: [ min:0, unit:'°', probe:{ device -> "${device.currentValue('temperature')}" } ],
    transportStatus: [ min:0, max:100, unit:'% playing', probe:{ device -> "${device.currentValue('transportStatus')}" == 'playing' ? 100 : 0 } ],
    valve: [ min:0, max:100, unit:'% open', probe:{ device -> "${device.currentValue('valve')}" == 'open' ? 100 : 0 } ],
    water: [ min:0, max:100, unit:'% wet', probe:{ device -> "${device.currentValue('water')}" == 'wet' ? 100 : 0 } ],
    windowBlind: [ min:0, max:100, unit:'% open', probe:{ device -> "${device.currentValue('windowBlind')}".contains('open') ? 100 : 0 } ],
    windowShade: [ min:0, max:100, unit:'% open', probe:{ device -> "${device.currentValue('windowShade')}".contains('open') ? 100 : 0 } ],
    voltage: [ min:0, unit:'V', probe:{ device -> "${device.currentValue('voltage')}" } ],

    // Non-standard attributes
    pm25: [ unit:'μg/m3', probe:{ device -> "${device.currentValue('pm25')}" } ],
    vocIndex: [ unit:'', probe:{ device -> "${device.currentValue('vocIndex')}" } ],
]
3 Likes

I consider myself to be a competent user. I really appreciate your skills.

2 Likes