Western Digital My Cloud

Could you perhaps clarify a bit more what you’re doing and where you are getting values from? The hex string: Is that the state of an SNMP sensor (trap)? Where is the Python script you’re referring to coming into the picture? Or are you just experimenting with a script (outside of HA) to parse the values?

You can’t “update” a sensor by setting a value from within HA if it’s set by another integration, neither can you add an attribute and value to it. I don’t know if you could do it via the API.

Personally, I’d just make a new template sensor where you can set the state and any attributes that you’d like all in one go based on the original sensor. You can control the icon, name and device class also there.

If you can give me the original sensor name I can type out a solution a bit later.

EDIT:

sensor:
  - platform: template
    sensors:
      wd_cloud_temp:
        friendly_name: "WD Cloud Temperature"
        unit_of_measurement: "°"
        value_template: "{{ (int(states('sensor.something')[-6:-4], base=16) - 48)*100 + (int(states('sensor.something')[-4:-2], base=16) - 48)*10 + (int(states('sensor.something')[-2:], base=16) - 48) }}"

Or:

template:
  - sensor:
      - name: "WD Cloud Temperature"
        unit_of_measurement: "°"
        state: "{{ (int(states('sensor.something')[-6:-4], base=16) - 48)*100 + (int(states('sensor.something')[-4:-2], base=16) - 48)*10 + (int(states('sensor.something')[-2:], base=16) - 48) }}"

Based on:

{% set sensor = '0x43656e746967726164653a3437200946616872656e686569743a313136' %}
{{ (int(sensor[-6:-4], base=16) - 48)*100 + (int(sensor[-4:-2], base=16) - 48)*10 + (int(sensor[-2:], base=16) - 48) }}
1 Like

Not sure why I didn’t think of a template sensor. I’m going to try that.

Thanks again. The value_template statement worked perfectly. I’m not sure why I didn’t think of template sensors. I have others. I was overcomplicating things.

1 Like

Hi all,

Firstly, i want to say thank you to everyone that has posted, it pointed me in the right direction allowing me to display some meaningful stats from my “MyCloud EX2 Ultra”

As such, i thought i’d share in the hope it may help others:

Final result: Love Lace UI card
EX2-card

How it works:
The data is collected via SNMP queries from Node Red, the payload formatted in a usable manner, and then sent to custom entities allowing the data to be exposed to Home Assistant / Love Lace UI.

I’m using a custom card (from HACS - vertical-stack-in-card), and the code is:

type: custom:vertical-stack-in-card
title: EX2 Ultra NAS
cards:
  - type: gauge
    name: Disk usage
    entity: sensor.nas_diskpercentused
    min: 0
    max: 100
    severity:
      green: 0
      yellow: 45
      red: 90
    needle: true
  - type: glance
    show_name: false
    entities:
      - entity: sensor.nas_temprature
        name: Temp
        icon: mdi:thermometer-low
      - entity: sensor.nas_uptime
        name: Uptime
        icon: mdi:chart-timeline-variant-shimmer
  - type: glance
    show_icon: false
    entities:
      - entity: sensor.nas_diskcapacity
        name: 'Capacity:'
      - entity: sensor.nas_diskusage
        name: 'Used:'
      - entity: sensor.nas_diskfree
        name: 'Free:'

And for the Node Red flow:

[{"id":"b724648aef7e329f","type":"group","z":"1b6a095.7f55cf7","name":"WD EX2 Ultra SNMP queries","style":{"stroke":"#92d04f","fill":"#e3f3d3","fill-opacity":"0.6","label":true,"color":"#0070c0"},"nodes":["88e133bc1808a21a","602f8d14ec73f71c","08b41def0b9a98f9","53997450868c9442","1c7a7b676efa1c55","ee8a5f4a75567bcb","16292bcf74abd204","e818a9bd9a324128","677a3b4e076e916e","a64e64e32b8c9bd4","2d99cc3126646528","a7732d0f158590e3","4d99a3f62dc1bd25","8f2f872054cb118e","641d3b2b9d9cf55f","8c465ff341c89415","e008579a086ab391","9236d42249b7e21b","05f0defdb3111549","be17066c2365d73e","586df903fb7afe81","3cafe0c987a42a02"],"x":34,"y":2739,"w":1392,"h":442},{"id":"88e133bc1808a21a","type":"snmp","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","host":"10.0.0.5","community":"public","version":"2c","oids":"1.3.6.1.2.1.25.1.1.0","timeout":5,"name":"NAS Up-Time","x":560,"y":2780,"wires":[["08b41def0b9a98f9","08b41def0b9a98f9"]]},{"id":"602f8d14ec73f71c","type":"inject","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":390,"y":2780,"wires":[["88e133bc1808a21a","88e133bc1808a21a"]]},{"id":"08b41def0b9a98f9","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Format SNMP payload","func":"// Timetick conversion below - used to caculate hours / days etc.\n//\n// timeticks / 100 = seconds\n// timeticks / 6000 = minutes\n// timeticks / 360000 = hours\n// timeticks / 8640000 = days\n\n// Code to convert \"up-time\" to both hours and days.\nmsg.UpTimeDays = (msg.payload[0].value/8640000).toFixed(1) +\" Days\"; //timeticks / 8640000 = days\nmsg.UpTimeHours = (msg.payload[0].value/360000 ).toFixed(2) +\" Hours\" ; //timeticks / 360000 = hours\n\n// Code to display the \"up-time\" in hours if it's less than 1 day\nif ((msg.UpTimeDays).includes(\"0.\")) {\n msg.Uptime = msg.UpTimeHours;\n } else {\n msg.Uptime = msg.UpTimeDays;\n}\n\n\nmsg.payload = msg.Uptime;\nreturn msg\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":2780,"wires":[["3cafe0c987a42a02","3cafe0c987a42a02"]]},{"id":"53997450868c9442","type":"inject","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":390,"y":2960,"wires":[["1c7a7b676efa1c55","1c7a7b676efa1c55"]]},{"id":"1c7a7b676efa1c55","type":"snmp","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","host":"10.0.0.5","community":"public","version":"2c","oids":"1.3.6.1.2.1.25.2.3.1.5.60,\n1.3.6.1.2.1.25.2.3.1.4.60,\n1.3.6.1.2.1.25.2.3.1.6.60","timeout":5,"name":"NAS Disk Info","x":560,"y":2960,"wires":[["ee8a5f4a75567bcb","ee8a5f4a75567bcb"]]},{"id":"ee8a5f4a75567bcb","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Format SNMP payload","func":"// The storage is in the format of: \"Allocation units\"\n// It took a while to work out how to convert, but the math is: \"disk alocation unit size\" multiplied by \"allocation units\" = disk size in bytes\n// With the capacity converted to a usable storage metric, we can perform some math to convert it to: mb / gb / tb\n\n// There are some other useful variables below - use whatever you find useful :)\n\n// Allocate the storage units to variables\nmsg.SizeAllocationUnits = (msg.payload[0].value)\nmsg.AllocationUnits = (msg.payload[1].value)\nmsg.StorageUsedUnits = (msg.payload[2].value)\n\n// Code to convert the disk \"allocation units\" to an actual usable size (\"disk alocation unit size\" multiplied by \"allocation units\")\n//msg.SizeB = (msg.SizeAllocationUnits * msg.AllocationUnits)\n//msg.SizeKB = (msg.SizeAllocationUnits * msg.AllocationUnits / 1024)\n//msg.SizeMB = (msg.SizeAllocationUnits * msg.AllocationUnits / 1024 / 1024).toFixed(2)\nmsg.SizeTB_raw_capacity = (msg.SizeAllocationUnits * msg.AllocationUnits / 1000 / 1000 / 1000 / 1000).toFixed(2)\nmsg.SizeGBString = (msg.SizeAllocationUnits * msg.AllocationUnits / 1024 / 1024 / 1024).toFixed(2)\nmsg.SizeGBComma = parseFloat(((msg.SizeAllocationUnits * msg.AllocationUnits / 1024 / 1024 / 1024).toFixed(0))).toLocaleString();\nmsg.SizeTB = (msg.SizeAllocationUnits * msg.AllocationUnits / 1024 / 1024 / 1024 / 1024).toFixed(2)\n\n\n// Code to convert the disk \"allocation units\" to an actual usable size (\"disk alocation unit size\" multiplied by \"allocation units\")\n//msg.UsedB = (msg.StorageUsedUnits * msg.AllocationUnits)\n//msg.UsedKB = (msg.StorageUsedUnits * msg.AllocationUnits / 1024)\n//msg.UsedMB = (msg.StorageUsedUnits * msg.AllocationUnits / 1024 / 1024).toFixed(2)\nmsg.UsedGBString = (msg.StorageUsedUnits * msg.AllocationUnits / 1024 / 1024 / 1024).toFixed(2)\nmsg.UsedGBComma = parseFloat((msg.StorageUsedUnits * msg.AllocationUnits / 1024 / 1024 / 1024).toFixed(0)).toLocaleString();\nmsg.UsedTB = (msg.StorageUsedUnits * msg.AllocationUnits / 1024 / 1024 / 1024 / 1024).toFixed(2)\n\n\n// a bit of math to determine the free space\n//msg.FreeB = (msg.SizeB - msg.UsedB)\n//msg.FreeKB = (msg.SizeKB - msg.UsedKB)\n//msg.FreeMB = (msg.SizeMB - msg.UsedMB).toFixed(2)\nmsg.FreeGBString = (msg.SizeGBString - msg.UsedGBString).toFixed(2)\nmsg.FreeGBComma = parseFloat((msg.SizeGBString - msg.UsedGBString)).toLocaleString();\nmsg.FreeTB = (msg.SizeTB - msg.UsedTB).toFixed(2)\n\n\n// a bit of code to determine the percentage of use / free space - variables for both\nmsg.PercentFree = ( ((msg.SizeAllocationUnits * msg.AllocationUnits) - msg.StorageUsedUnits * msg.AllocationUnits) / (msg.SizeAllocationUnits * msg.AllocationUnits) * 100).toFixed(0)\nmsg.PercentUsed = ((msg.StorageUsedUnits * msg.AllocationUnits)/ (msg.SizeAllocationUnits * msg.AllocationUnits)* 100).toFixed(0)\n\n\nreturn msg\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":2960,"wires":[["a7732d0f158590e3","641d3b2b9d9cf55f","8f2f872054cb118e","e008579a086ab391","be17066c2365d73e","a7732d0f158590e3","8f2f872054cb118e","641d3b2b9d9cf55f","e008579a086ab391","be17066c2365d73e"]]},{"id":"16292bcf74abd204","type":"inject","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":390,"y":3140,"wires":[["e818a9bd9a324128","e818a9bd9a324128"]]},{"id":"e818a9bd9a324128","type":"snmp","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","host":"10.0.0.5","community":"public","version":"2c","oids":"1.3.6.1.4.1.5127.1.1.1.8.1.10.1.5.1,\n1.3.6.1.4.1.5127.1.1.1.8.1.10.1.5.2","timeout":5,"name":"NAS System Temperature","x":590,"y":3140,"wires":[["677a3b4e076e916e","677a3b4e076e916e"]]},{"id":"677a3b4e076e916e","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Format SNMP payload","func":"// Code to get the disk tempratures, fix up the string and display the average temp.\nmsg.Disk1 = parseInt((msg.payload[0].value).replace(\"Centigrade:\",\"\"));\nmsg.Disk2 = parseInt((msg.payload[1].value).replace(\"Centigrade:\",\"\"));\nmsg.AverageDiskTemp = ((msg.Disk1 + msg.Disk2) /2);\n\nmsg.payload = msg.AverageDiskTemp;\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":840,"y":3140,"wires":[["a64e64e32b8c9bd4","a64e64e32b8c9bd4"]]},{"id":"a64e64e32b8c9bd4","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.temprature","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.temprature"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":"c"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.temprature","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1280,"y":3140,"wires":[[]]},{"id":"2d99cc3126646528","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.diskcapacity","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskcapacity"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"tb"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskcapacity","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1280,"y":2840,"wires":[[]]},{"id":"a7732d0f158590e3","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Payload","func":"//msg.payload = msg.SizeTB;\nmsg.payload = msg.SizeTB_raw_capacity;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":2840,"wires":[["2d99cc3126646528","2d99cc3126646528"]]},{"id":"4d99a3f62dc1bd25","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.diskfree","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskfree"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"tb"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskfree","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1270,"y":2960,"wires":[[]]},{"id":"8f2f872054cb118e","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.FreeTB;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":2960,"wires":[["4d99a3f62dc1bd25","4d99a3f62dc1bd25"]]},{"id":"641d3b2b9d9cf55f","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.UsedTB;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":2900,"wires":[["8c465ff341c89415","8c465ff341c89415"]]},{"id":"8c465ff341c89415","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.diskusage","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskusage"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"tb"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskusage","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1280,"y":2900,"wires":[[]]},{"id":"e008579a086ab391","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.PercentFree;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":3020,"wires":[["9236d42249b7e21b","9236d42249b7e21b"]]},{"id":"9236d42249b7e21b","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.diskpercentfree","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskpercentfree"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskpercentfree","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1290,"y":3020,"wires":[[]]},{"id":"05f0defdb3111549","type":"poll-state","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Poll NAS power switch","server":"c619ecc5.a1f0d","version":2,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"updateinterval":"900","updateIntervalType":"num","updateIntervalUnits":"seconds","outputinitially":true,"outputonchanged":true,"entity_id":"switch.lounge_nas_energy","state_type":"str","halt_if":"on","halt_if_type":"str","halt_if_compare":"is","outputs":2,"x":160,"y":2960,"wires":[["88e133bc1808a21a","1c7a7b676efa1c55","e818a9bd9a324128","1c7a7b676efa1c55","e818a9bd9a324128","88e133bc1808a21a"],[]]},{"id":"be17066c2365d73e","type":"function","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.PercentUsed;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1100,"y":3080,"wires":[["586df903fb7afe81","586df903fb7afe81"]]},{"id":"586df903fb7afe81","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.diskpercentused","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskpercentused"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskpercentused","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1300,"y":3080,"wires":[[]]},{"id":"3cafe0c987a42a02","type":"ha-entity","z":"1b6a095.7f55cf7","g":"b724648aef7e329f","name":"nas.uptime","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.uptime"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.uptime","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1270,"y":2780,"wires":[[]]},{"id":"c619ecc5.a1f0d","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"}]

For others somewhat new to this, let me save you my hour of trial and error finding the correct syntax. Here’s what did it for me:

sensor:
- platform: snmp
    name: "NAS System Temp"
    host: 192.168.9.100
    baseoid: 1.3.6.1.4.1.5127.1.1.1.8.1.7.0
    community: !secret SNMP
    version: "2c"
    scan_interval: 60
- platform: template
    sensors:
      nas_system_temperature:
        friendly_name: "NAS System Temperature"
        unit_of_measurement: "°F"
        value_template: "{{ (int(states('sensor.nas_system_temp')[-6:-4], base=16) - 48)*100 + (int(states('sensor.nas_system_temp')[-4:-2], base=16) - 48)*10 + (int(states('sensor.nas_system_temp')[-2:], base=16) - 48) }}"

Having said that, there is still an issue with the above code. Right now it displays 1096 as the value based on the HEX string 0x43656e746967726164653a3336200946616872656e686569743a3936
Which makes sense seeing as 3a is ASCI for : (the next char after 9). So the temp is only 2 digits instead of 3. (And we get 10 (the next number after 9) as the first digit)
How can we programmatically catch the temp being only 2 digits? In every case, the string will end in 3axxyyzz. Where 3a is the colon HEX code, and then xx, yy and zz are the 3 HEX digits of the temperature, and zz is an optional character if the temp is under 100 degrees F.
(And potentially (since I am European), we can also then write a similar statement for Celsius which starts at the first 3a and ends with 20 (space). But then we need to check it every 2 chars (and not see a 3a when really it’s 03:a4 or something))
Or could we convert the whole string from HEX to an ASCII sentence and then just parse out the temp by looking for the actual : in the string? Using a value.split(‘Fahrenheit:’) or something?

I know what’s needed, I just lack the syntactical skills to execute it.

I can’t type out a full solution now, but here are some hints:

To convert a hex string to ASCII, there’s no Jinja2 or HA templating built-in ways. Luckily, Petro has typed up the algorithm.

Once you have that, you can use a regex.

I just quickly made a regex in Python (experiment with this in your template editor):

import re
h = "0x43656e746967726164653a3336200946616872656e686569743a3936"
s = bytearray.fromhex(h[2:]).decode()  # 'Centigrade:36 \tFahrenheit:96'
m = re.search(":(\d+).+?\:(\d+)", s)
m.groups()  # ('36', '96')

Thanks for this. I like the vertical stack, and used that on mine as well.

I also used your NodeRed code, as the SNMP from HA kept failing (sensors Unavailable. And sometimes they’d suddenly show up days later, but not consistently).
I did edit a few things. Like updating your temp units to “°C” (Which allowed HA to show it to me in the GUI as °F).
In addition, I completely redid your disk space. Rather than looking at allocation units, I grabbed 1.3.6.1.4.1.5127.1.1.1.8.1.9.1.5.1 for disk size (which returns 3.6T for my 4TB system), and just stripped the T from it. At these sizes, I’m not too concerned about more decimals. But that makes the function easier to get total, used and free size.
And since I didn’t have a switch to look at if the NAS was up, I just (for simplicity’s sake) used an inject node to kick this off every 15 minutes.
Here’s my code in case anyone else wants to use it

[{"id":"b724648aef7e329f","type":"group","z":"9e354d802036d78a","name":"WD EX2 Ultra SNMP queries","style":{"stroke":"#92d04f","fill":"#e3f3d3","fill-opacity":"0.6","label":true,"color":"#0070c0"},"nodes":["88e133bc1808a21a","602f8d14ec73f71c","08b41def0b9a98f9","53997450868c9442","1c7a7b676efa1c55","ee8a5f4a75567bcb","16292bcf74abd204","e818a9bd9a324128","677a3b4e076e916e","a64e64e32b8c9bd4","2d99cc3126646528","a7732d0f158590e3","4d99a3f62dc1bd25","8f2f872054cb118e","641d3b2b9d9cf55f","8c465ff341c89415","e008579a086ab391","9236d42249b7e21b","be17066c2365d73e","586df903fb7afe81","3cafe0c987a42a02","f6bd7d82dc07d2cb","deebc32c42f350cd","fb72868fa2e7cceb","18b0551be066270f","917bcf570eb10663","e1ee6e618dcf3da8"],"x":34,"y":79,"w":1152,"h":562},{"id":"88e133bc1808a21a","type":"snmp","z":"9e354d802036d78a","g":"b724648aef7e329f","host":"hostname","community":"string","version":"2c","oids":"1.3.6.1.2.1.25.1.1.0","timeout":5,"name":"NAS Up-Time","x":360,"y":120,"wires":[["08b41def0b9a98f9"]]},{"id":"602f8d14ec73f71c","type":"inject","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":120,"wires":[["88e133bc1808a21a"]]},{"id":"08b41def0b9a98f9","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Format SNMP payload","func":"// Timetick conversion below - used to caculate hours / days etc.\n//\n// timeticks / 100 = seconds\n// timeticks / 6000 = minutes\n// timeticks / 360000 = hours\n// timeticks / 8640000 = days\n\n// Code to convert \"up-time\" to both hours and days.\nmsg.UpTimeDays = (msg.payload[0].value/8640000).toFixed(1) +\" Days\"; //timeticks / 8640000 = days\nmsg.UpTimeHours = (msg.payload[0].value/360000 ).toFixed(2) +\" Hours\" ; //timeticks / 360000 = hours\n\n// Code to display the \"up-time\" in hours if it's less than 1 day\nif ((msg.UpTimeDays).includes(\"0.\")) {\n msg.Uptime = msg.UpTimeHours;\n } else {\n msg.Uptime = msg.UpTimeDays;\n}\n\n\nmsg.payload = msg.Uptime;\nreturn msg\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":120,"wires":[["3cafe0c987a42a02"]]},{"id":"53997450868c9442","type":"inject","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":300,"wires":[["1c7a7b676efa1c55"]]},{"id":"1c7a7b676efa1c55","type":"snmp","z":"9e354d802036d78a","g":"b724648aef7e329f","host":"hostname","community":"string","version":"2c","oids":"1.3.6.1.4.1.5127.1.1.1.8.1.9.1.5.1,\n1.3.6.1.4.1.5127.1.1.1.8.1.9.1.6.1","timeout":5,"name":"NAS Disk Info","x":360,"y":300,"wires":[["ee8a5f4a75567bcb"]]},{"id":"ee8a5f4a75567bcb","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Format SNMP payload","func":"msg.SizeTB = parseFloat((msg.payload[0].value).replace(\"T\",\"\"))\nmsg.FreeTB = parseFloat((msg.payload[1].value).replace(\"T\",\"\"))\nmsg.UsedTB = (msg.SizeTB - msg.FreeTB).toFixed(1)\n\nmsg.PercentUsed = ((msg.UsedTB / msg.SizeTB) * 100).toFixed(0)\nmsg.PercentFree = ((msg.FreeTB / msg.SizeTB) * 100).toFixed(0)\n\nreturn msg\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":300,"wires":[["a7732d0f158590e3","641d3b2b9d9cf55f","8f2f872054cb118e","e008579a086ab391","be17066c2365d73e"]]},{"id":"16292bcf74abd204","type":"inject","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Query","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":480,"wires":[["e818a9bd9a324128"]]},{"id":"e818a9bd9a324128","type":"snmp","z":"9e354d802036d78a","g":"b724648aef7e329f","host":"hostname","community":"string","version":"2c","oids":"1.3.6.1.4.1.5127.1.1.1.8.1.7.0,\n1.3.6.1.4.1.5127.1.1.1.8.1.10.1.5.1,\n1.3.6.1.4.1.5127.1.1.1.8.1.10.1.5.2","timeout":5,"name":"NAS System Temperature","x":390,"y":480,"wires":[["677a3b4e076e916e"]]},{"id":"677a3b4e076e916e","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Format SNMP payload","func":"// Code to get the disk temperatures, fix up the string and display the average temp.\nmsg.System = parseInt((msg.payload[0].value.split('Fahrenheit:')[1]));\nmsg.Disk1 = parseInt((msg.payload[1].value).replace(\"Centigrade:\",\"\"));\nmsg.Disk2 = parseInt((msg.payload[2].value).replace(\"Centigrade:\",\"\"));\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":480,"wires":[["f6bd7d82dc07d2cb","deebc32c42f350cd","18b0551be066270f"]]},{"id":"a64e64e32b8c9bd4","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.disk1","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.disk1"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":"°C"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.temprature","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1020,"y":480,"wires":[[]]},{"id":"2d99cc3126646528","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.diskcapacity","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskcapacity"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"TB"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskcapacity","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1040,"y":180,"wires":[[]]},{"id":"a7732d0f158590e3","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"//msg.payload = msg.SizeTB;\nmsg.payload = msg.SizeTB;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":180,"wires":[["2d99cc3126646528"]]},{"id":"4d99a3f62dc1bd25","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.diskfree","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskfree"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"TB"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskfree","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1030,"y":300,"wires":[[]]},{"id":"8f2f872054cb118e","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.FreeTB;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":300,"wires":[["4d99a3f62dc1bd25"]]},{"id":"641d3b2b9d9cf55f","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.UsedTB;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":240,"wires":[["8c465ff341c89415"]]},{"id":"8c465ff341c89415","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.diskusage","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskusage"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"TB"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskusage","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1040,"y":240,"wires":[[]]},{"id":"e008579a086ab391","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.PercentFree;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":360,"wires":[["9236d42249b7e21b"]]},{"id":"9236d42249b7e21b","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.diskpercentfree","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskpercentfree"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskpercentfree","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1050,"y":360,"wires":[[]]},{"id":"be17066c2365d73e","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.PercentUsed;\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":420,"wires":[["586df903fb7afe81"]]},{"id":"586df903fb7afe81","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.diskpercentused","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.diskpercentused"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:harddisk"},{"property":"unit_of_measurement","value":"%"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.diskpercentused","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1060,"y":420,"wires":[[]]},{"id":"3cafe0c987a42a02","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.uptime","server":"c619ecc5.a1f0d","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.uptime"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":""},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[{"property":"entity_id","value":"sensor.nas.uptime","valueType":"str"}],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"$entity().state ? \"on\": \"off\"","outputPayloadType":"jsonata","x":1030,"y":120,"wires":[[]]},{"id":"f6bd7d82dc07d2cb","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.Disk1;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":480,"wires":[["a64e64e32b8c9bd4"]]},{"id":"deebc32c42f350cd","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.Disk2;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":540,"wires":[["fb72868fa2e7cceb"]]},{"id":"fb72868fa2e7cceb","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.disk2","server":"4f28a876.524b58","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.disk2"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":"°C"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":1020,"y":540,"wires":[[]]},{"id":"18b0551be066270f","type":"function","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"Payload","func":"msg.payload = msg.System;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":860,"y":600,"wires":[["917bcf570eb10663"]]},{"id":"917bcf570eb10663","type":"ha-entity","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"nas.temp","server":"4f28a876.524b58","version":2,"debugenabled":false,"outputs":1,"entityType":"sensor","config":[{"property":"name","value":"nas.temp"},{"property":"device_class","value":""},{"property":"icon","value":"mdi:nas"},{"property":"unit_of_measurement","value":"°F"},{"property":"state_class","value":""},{"property":"last_reset","value":""}],"state":"payload","stateType":"msg","attributes":[],"resend":true,"outputLocation":"payload","outputLocationType":"none","inputOverride":"allow","outputOnStateChange":false,"outputPayload":"","outputPayloadType":"str","x":1020,"y":600,"wires":[[]]},{"id":"e1ee6e618dcf3da8","type":"inject","z":"9e354d802036d78a","g":"b724648aef7e329f","name":"15 Mins","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"900","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":140,"y":200,"wires":[["88e133bc1808a21a","1c7a7b676efa1c55","e818a9bd9a324128"]]},{"id":"c619ecc5.a1f0d","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":false,"cacheJson":true,"heartbeat":false,"heartbeatInterval":"30"},{"id":"4f28a876.524b58","type":"server","name":"Home Assistant","version":2,"addon":true,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30}]
1 Like

I know I’m coming in late on this.

I know nothing about Unix so the things above are way above my head, but I am exploring them. I only have the single drive MyCloud box that I’ve been told is now no longer supported by WD! So SNMP won’t work if I have read stuff correctly. So i’ll be looking at the stats thing from EventuallyFixed (Why create the stats directory 4 levels down below mnt? my mnt has nothing in it!).

However, I’ve done a little messing around and found that my WD drive, in SSH, does the nc thing and I can type in a message that I can receive in Node-Red TCP Input node. So I was thinking, is there a way to pull all the stats I want by a script that runs say hourly and then passes that to Node-Red as a comma separated list? Once in Node-Red I would know how to deal with it.

I know nothing about unix or php but am trying to follow what you have done here.

php is running on my device as I can do the phpinfo() thing.

I’ve created a directory under /var/www called stats

My Cloud drive does not have anything under /mnt. Do I still need to do the whole HD/HD_a2/Nas_Prog/stats thing, or can i make a shorter path? I’ll do it anyway, but I don’t understand why.

My pressing question for now is where do I put the php files?

Edit: So I’ve now done the HD/HD_a2… thing as well as the ln thing. I’ve also created the disk.php file in the stats directory, modified to suit what I get when I type df. It works if I run it locally. Now I’m assuming i can go to any browser and type in http://192.168.x.y/stats/disk.php I would see the result of executing the php file. but all I get is Not Found blah blah.
I’ve tried making the disk.php executable (chmod) but still no joy. I’d like to get this working before I move on to the HA bit.

Hi Graham,

Wow, this thread has really exploded since I last looked! :smiley:

My NAS device is an EX4100. The file system layout my device has been the same since OS3 through to OS5:

  • /mnt/HD/HD_a2 contains the user directories, and other system folders and files
  • /shares contains unix symbolic links to the user areas only

Because the file system layout of your device is different to mine, I guess that you don’t have an EX4100. What is the model you have?

I’m writing this from memory, but the steps are

  1. Create a folder in an area where the Western Digital OS will not wipe it upon a reboot. For example, you might create a user (and therefore a folder on the file system) for this purpose
  2. Put the php files inside it
  3. ssh on to the device
  4. At the unix prompt, find the user share folder and note the full path to it.
  5. Go to the /var/www folder, and create a unix symbolic link to the folder that contains the php files

Assuming that the web server of the NAS

  • Can run php code (it can, as you said above)
  • Is able to see the directory containing the php files (which is what the symbolic link should achieve)
  • Normally serves files from /var/www (which is pretty standard in the unix world, but this is WD are dealing with…)
  • And all of the unix call-outs contained within the php code are available in the OS

It all ought to hang together, and just work.

Thanks for getting back to me.

The device is just a WD My Cloud network drive. I have 2 of them, about 8 years old, one as my general backup disk and the other as an NFS/SMB server for my security cameras. The UI gives no other clue as to the model.

You are right about stuff getting deleted on reboot!

I’ve now created a Share called Graham with a sub directory called stats and put the disk.php in it. It’s good being there as it’s permanent and I can edit it from windows with Notepad++.

In the ssh terminal I can type “php disk.php” and I get the JSON string output as expected.

I’ve created the symbolic link using “ln -s /shares/Graham/stats /var/www/stats” and can now see the stats directory under www with the disk.php in it. I can also run it from there.

I assumed that I could then type “http://192.168.xxx.yyy/stats/disk.php” into a browser and I would see the JSON output there. That would then give me the confidence all was well and I would move on to the HA side of things, but still I am getting the following error message

"Not Found
The requested URL /stats/disk.php was not found on this server.

Additionally, a 404 Not Found error was encountered while trying to use an ErrorDocument to handle the request."

Since the browser URL is the same format as per your example in the HA code, I assume that will not work either. Perhaps I am just wrong on this point. Or, is there something else I must do in ssh to enable the URL to work?

On a different track, I have piped the disk.php into “nc 192.168.xxx.zzz port” and successfully got the JSON into a Node-Red TCP Input node. Perhaps there’s a way to get a script that runs on the MyCloud drive every hour, say, that does just that, but my knowledge of unix is minimal.

Thanks again.

Hmmm. One of these must be true…

  1. The web server on your machine does not serve from /var/www
  2. The web server cannot see the directory /shares/Graham/stats
  3. The web server can serve from /var/www, but cannot execute php from /var/www

I suggest that you test point 1 by creating a ‘Hello World’ html file, at /var/www/helloworld.html, then try & navigate to “http://192.168.xxx.yyy/helloworld.html”

You can test Point 2 by creating the same file in /shares/Graham/stats, and navigating to http://…/stats/helloworld.html

If it works, this is a valid place for html files, and the web server of the machine is pointed at it. It does not confirm that .php files can run from here, but it’s a start.

Perhaps using an .htaccess file here can help?

If not, there is some discovery for you to do, to find where the web server root directory is. Perhaps the output of the phpinfo.php can help…

If you want to go down the scripting route, you’ll need to do something like…

  • First create and then distribute your ssh keys to the machines, to allow a passwordless ssh log in.
  • Create a script, probably using a heredoc, to execute on the target machine the commands you want in the ssh session.
  • Create a ‘shell_command’ configuration section in your configuration.yaml
  • Create an automation in HASS to execute the script referenced in thh shell_command.

In case you want to use them, I have put my shell scripts in my GitHub repository.

Thanks.

Tried the Hello World and can confirm it works with “IP/Graham/stats/helloworld.html” but not with “IP/stats/helloworld.html” nor “IP/helloworld.html” even if I put the file in /var/www.

Thinking about it, to get into the regular GUI I have to enter a username and password. Then the URL is displayed as “IP/UI/” wherever I navigate around the system. I can see what assume to be all the directories/files under /var/www but it’s quite complex in structure. I’ve tried locating the php file in various directories and messing with permissions and groups but no joy. I think I’ll give up on that approach.

I’m still thinking of just SSHing in after a reboot and running a never ending script calling the php and sending the output via TCP to be received by Node-Red. That avoids any of the SSH stuff in your original post which with my level of unix just went above my head. I just need to research crontab or a do while true { php, sleep} sort of script now.

It’s been fun learning about unix and php though so not time wasted.

The problem with a cron task on the NAS is that (at least on the WD EX4100) you cannot get at it in a permanent way: On my device, the crontab is completely rewritten at ~3am.

So I got around that by using Home Assistant Automations as a ‘cron’, that called a script. That script had a command to ssh in to the NAS (a password-less log in using ssh keys) and use a heredoc to execute the shell scripts I referred to above.

Oh, I guess that IP/Graham/stats/phpinfo.php does not work?

I’ve got crontab working every 2 minutes (for now) and it doesn’t appear to be stopped/deleted after 24hrs. I’m using it to run your (mostly) php script for the disk sizes and then nc the json output to a Node-red TCP input node listening on a particular port. This then just passes it on to an mqtt output node.
The crontab line is

*/2 * * * * php /shares/myshare/disk.php | nc -w 1 192.168.xxx.yyy 12345

In the configuration.yaml I have a sensor which picks up the Percentage Used…

sensor:
# MQTT sensors to receive data fromt the WDMyCam Cloud (See Node-Red flow 5)
  - platform: mqtt
    unique_id: sunny_mqtt_0022
    state_topic: disk/disk/wdcamcloud
    name: "wdcamcloud_percent_used"
    unit_of_measurement: '%'
    value_template: "{{value_json.disk.percent.used}}"

I haven’t tried a reboot but it’s quite a simple thing to re-input. EDIT: Done a reboot and the crontab entries persist. :slight_smile:

Now I’ve proven it works, I’m going to add more of your scripts and sensors. Thanks for the pointers.

Did somebody try to do this for WD MyBool Live Duo?
I can SSH into the system and the memory stuff works, but e.g. there is no fan_control (well, system has no fan) and also the storage output is different.

The discussion makes we wonder if it would not be possible to install a MQTT client on the MBL, but that probably is prevented by WD for god knows why. Really a pity that there is no component for this until now — probably not enough users.

Can someone help me with this template?
On the snmp i receive from the first HD the value 136G, and 3.8T from the second. So, the problem is, i need to replace both letters, T and G, and on the second HD i need multiply by 1000 to get the equivalent of GBs of the first drive. But i dont know how to do this.
Heres the code:

- platform: snmp
  name: 'Free space 2 NAS disk'
  host: 192.168.68.107
  baseoid: 1.3.6.1.4.1.5127.1.1.1.8.1.9.1.6.2
  community: 'public'
  version: "2c"
  value_template: "{{ value.replace('G','') }}"
  unit_of_measurement: "GB"
  accept_errors: true
  scan_interval: 10

Great job on the sensors functionality guys.
What about buttons to send a coomand to Hibernate the WDmycloudmirror?
And then another button to wake it up, maybe using WOL?

I’ve been using the command line approach for a while now without any problems, but the latest HA release 2023.6 has some breaking changes that require some adjustments to the yaml.

THIS NEEDS TO BE CHANGED BEFORE UPGRADING TO RELEASE 2023.8 !

Take a look at the breaking change concerning command line :
The Command Line integration changes its YAML configuration format from an old-style platform configuration to a more modern integration-style configuration format.

So where it used to be:

sensor:
  # NAS Disk Space Percent Used
  - platform: command_line
    name: DATASTATION_disk_perc_used
    unit_of_measurement: '%'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 5 | sed 's/%//g'
  # NAS Disk Space Used
  - platform: command_line
    name: DATASTATION_disk_space_used
    unit_of_measurement: 'MB'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df -m | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 3
  # NAS Disk Space Free
  - platform: command_line
    name: DATASTATION_disk_space_free
    unit_of_measurement: 'MB'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df -m | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 4
  # NAS Board Temperature
  - platform: command_line
    name: DATASTATION_board_temp
    unit_of_measurement: '°C'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep Current | cut -d' ' -f 4
  # NAS HD0 Temperature
  - platform: command_line
    name: DATASTATION_hd0_temp
    unit_of_measurement: '°C'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep hd0 | cut -d' ' -f 2 | cut -d'=' -f 2
  # NAS HD1 Temperature
  - platform: command_line
    name: DATASTATION_hd1_temp
    unit_of_measurement: '°C'
    command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep hd1 | cut -d' ' -f 2 | cut -d'=' -f 2

… it now needs to be:

command_line:
  # NAS Disk Space Percent Used
  - sensor:
      name: DATASTATION_disk_perc_used
      unit_of_measurement: '%'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 5 | sed 's/%//g'
  # NAS Disk Space Used
  - sensor:
      name: DATASTATION_disk_space_used
      unit_of_measurement: 'MB'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df -m | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 3
  # NAS Disk Space Free
  - sensor:
      name: DATASTATION_disk_space_free
      unit_of_measurement: 'MB'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] df -m | sed -n '/HD_a2/s/ \+/ /gp' | cut -d' ' -f 4
  # NAS Board Temperature
  - sensor:
      name: DATASTATION_board_temp
      unit_of_measurement: '°C'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep Current | cut -d' ' -f 4
  # NAS HD0 Temperature
  - sensor:
      name: DATASTATION_hd0_temp
      unit_of_measurement: '°C'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep hd0 | cut -d' ' -f 2 | cut -d'=' -f 2
  # NAS HD1 Temperature
  - sensor:
      name: DATASTATION_hd1_temp
      unit_of_measurement: '°C'
      command: ssh -i /ssl/wdmycloudhass -oHostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no -q [email protected] fan_control -g 0 | grep hd1 | cut -d' ' -f 2 | cut -d'=' -f 2

Hi everyone,

So I have an old WD mycloud mirror which I am wanting to add into home assistant to monitor its temps and disk health.

I have managed to reverse engineer the web API and create a basic python module that can login and fetch the system data, to then return as a JSON.

I am just in the process of learning how to upload this module to PyPi

If you want to take a look I have it on GitHub and feel free to make a PR or submit an issue for ideas and such.

Cheers!

Edit:

Forgot to say, my NAS does not seem to support SNMP which is why I did this - Also thought it would be a fun little project