Synology Download Station sensors

For me one of always missing integrations was Synology Download Station. So I decided to fill in the gap… and here it is… sort of.
Since I’m not familiar with python, I did not took challenge to build proper integration, but I figured out how I can link with SDS using standard tools available for everyone within HA. It ended with creation of yaml package containing everything that is needed to integrate SDS into HA. Before you begin, however, a few words of warning:

  • it is entirely based on sensor created in configuration.yaml created using mix of REST sensors, shell commands, some scripts and automations, so it probably not as efficient as it would be while using proper integration.
  • since I use rest sensors to obtain information from SDS and use other set of sensors to process this data, propagation of information takes time. I believe rest sensors are updated every 15 seconds and it takes up to 3 cycles to update ‘child’ sensors. Not ideal, but given the fact that sometimes file downloads are very long process I believe this speed of update is acceptable. I no more use REST sensors, being replaced by shell commands that are invoked every 10 seconds. Responce from these commands is instantly processed by file sensors, so overal whole ‘integration’ is way more responsive and (almost) always provides consistent download tasks informtion.
  • WARNING: since I found no way to template secrets, configuration of this ‘integration’ is hardcoded in sensors. Especially it concerns user ID and password used to access Synology NAS via API and also exposes session token (required to access API after logging in) as one of sensors ! ! !
  • since using this method I can’t create dynamically sensors, these are somehow reusable. You should consider each sensor as representing download slot rather that actual individual task. It means that these sensors are ‘reusable’ and if one download is completed and removed from SDS, this slot might be used for other pending download task, effectively changing history of task from old to new one… especially inconvenient for charts (like download speed). Also when task is removed or added to SDS it might cause some inconsistency of displayed data, before sensors values changes in up to 3 iterations I mentioned in point #1.

So, to the actual implementation:
You need to copy all the code from gist below into download.yaml file inside your config directory (or obviously modify setup to your liking! :slight_smile: )

  • Since everything is packaged into single download.yaml package file, your configuration just need to be updated. Since now I’m using temporary files to store data from shell commands, it is required to create /sds folder under your config directory and whitelist it, so it can be accessed by scripts and file sensors. Required changes to configuration.yaml file are listed below:
homeassistant:
  packages:
    download: !include download.yaml
  whitelist_external_dirs:
    - /config/sds
  • Additional step for system preparation is to create set of files (should be emty) in config/sds folder. These files will be used by shell commands to store temporary data. I found commands failing if files are not created prior to running them for the first time, so this is mandatory step. Files to be created:
sid.json
sds_tasks_list.json
sds_task_0.json
sds_task_1.json
sds_task_2.json
sds_task_3.json
sds_task_4.json
sds_task_5.json
sds_task_6.json
sds_task_7.json
sds_task_8.json
sds_task_9.json
  • within download.yaml, you need to update 2 first sensors (sds_login and sds_tasks_list) all 12 shell_commands replacing following statements with actual data:
 _SDS_IP_    - IP address of your NAS
 _SDS_PORT_  - port to connect on. in standard setup it is:
               5000 for Synology Diskstation Manager or
               8000 for Synology Download Station
               either of these 2 can be used
 _SDS_USER_  - DSM user with permission to use SDS
 _SDS_PASS_  - password for above user
  • if you have proper ssl access configgured on your NAS, you can change protocol to hppts and update port accordingly (5001 or 8001).
  • you also need to update _SDS_IP_ and _SDS_PORT_ within all sds_task_# sensors.
  • I created sensor templates for 10 download slots. All corresponding to specific download slot sensors have name ending with _#, where # represent number of slot, starting with 0 and ending with 9. If you do not expect such number of slots to be used you can safely delete some and decrease number of created sensors. If you download more, you can also add new sensors with # starting from 10…

Following sensors are created:

  • sensor.sds_login - it is used to initially log on to SDS and obtain the API token. Not used elsewhere.
  • sensor.sds_tasks_list - contain list of basic data for all download tasks. This list will be empty if no downloads or might contain information about more than 10 tasks, but the tasks 10+ will be disregarded (until you create additional sensors). Otherwise this sensor has no use.
  • sensor.sds_task_# - contains detailed information about download task as reported via SDS API. Based on information from this sensor all other sensors are created. If you feel confident with templating, you can uses these sensors directly!
  • sensor.sds_sid - this is the sensor that holds API token used by rest sensors to retrieve data via API. No for direct use.
  • sensor.sds_sid_2 - temporary sensor, not to be used
  • sensor.sds_task_id_# - set of sensors used by SDS API to identify unique tasks. Used as reference by other sensors only.
  • sensor.sds_task_name_# - name of downloaded file
  • sensor,sds_task_size_# - size of downloaded file in MB
  • sensor.sds_task_size_downloaded_# - size of already downloaded part of file in MB
  • sensor.sds_task_completed_# - download progress in %
  • sensor.sds_task_speed_down_# - task download speed in kbps
  • sensor.sds_task_speed_up_# - task upload speed in kbps
  • sensor.sds_task_status_# - status of task (downloading, error, finished, unknown for just started, unavailable for empty slot)
  • sensor.sds_task_state_# - True if download task is active

Set of statistical sensors, useful for example to dynamically scale some charts, or dynamic color representation:

  • sensor.sds_max_download - sensor reporting download speed of fastest task
  • sensor.sds_avg_download - sensor reporting average download speed of all tasks
  • sensor.sds_min_download - sensor reporting download speed of slowest task (frequently 0)
  • sensor.sds_max_upload - sensor reporting upload speed of fastest task
  • sensor.sds_avg_upload - sensor reporting average upload speed of all tasks
  • sensor.sds_min_upload - sensor reporting upload speed of slowest task (frequently 0)
  • sensor.sds_max_transfer - representing fastest one of upload and download, useful if you want to use one graph to display both and have uniform scale.

As you can see package I prepared contains lots of sensors, in your particular implementation perhaps some might be useless, so can be safely deleted, decluttering configuration.

As a bonus I’m attaching template of lovelace card I created to use with this ‘integration’. It requires following components to be installed:

  • button-card
  • custom:mini-graph-card
  • custom:config-template-card
  • custom:button-card
    Screenshot 2020-06-11 at 7.53.33

Following code is for download slot 0. To create similar cards for subsequent slots you need to replace in the names of sensors use ‘_0’ with proper number. Card is autohiding, if slot not in use, to keep UI declustered.

card:
  aspect_ratio: 1.3/1
  custom_fields:
    bar:
      card:
        direction: right
        entities:
          - entity: sensor.sds_task_completed_0
        height: 25px
        max: 100
        min: 0
        positions:
          icon: 'off'
          indicator: 'off'
          minmax: 'off'
          name: 'off'
          target: 'off'
          value: inside
        severity:
          - color: '#7b55d5'
            from: 0
            to: 25
          - color: '#fc70f3'
            from: 25
            to: 50
          - color: '#00b8fe'
            from: 50
            to: 75
          - color: '#7cff73'
            from: 75
            to: 100
        type: 'custom:bar-card'
        width: 10%
    graph:
      card:
        card:
          entities:
            - entity: sensor.sds_task_speed_down_0
              color: var(--greenish)
              state_adaptive_color: true
              name: Download
            - entity: sensor.sds_task_speed_up_0
              color: var(--light-magenta)
              state_adaptive_color: true
              name: Upload
              y_axis: secondary
              show_state: true
          height: 100
          hours_to_show: 1
          line_width: 2
          points_per_hour: 600
          show:
            points: false
            fill: fade
            icon: false
            name: false
            labels: false
            labels_secondary: false
          type: 'custom:mini-graph-card'
        entities:
          - sensor.sds_max_download
          - sensor.sds_avg_download
          - sensor.sds_task_speed_down_0
          - sensor.sds_task_speed_up_0
        type: 'custom:config-template-card'
        variables:
          - 'states[''sensor.sds_max_download''].state'
          - 'states[''sensor.sds_avg_download''].state'
  entity: sensor.sds_task_name_0
  hold_action:
    action: none
  show_name: false
  show_state: true
  styles:
    card:
      - padding-left: 10px
      - padding-right: 10px
    custom_fields:
      bar:
        - filter: opacity(100%)
        - overflow: unset
        - margin-left: '-51%'
        - width: 105%
      graph:
        - filter: opacity(100%)
        - overflow: unset
    state:
      - color: var(--cyanish)
    grid:
      - grid-template-areas: '"s" "graph" "bar'
      - grid-template-columns: 1fr
      - grid-template-rows: 1fr 1fr
  type: 'custom:button-card'
conditions:
  - entity: sensor.sds_task_id_0
    state_not: '0'
type: conditional

I also created entire view, showing at a glance status of all download slots (more like in traditional clients), one per row:

This view uses following elements:
- multiple-entity-row
- config-template-card
- bar-card
- mini-graph-card
- layout-card

Here is the complete code for this view (should be used in panel mode):

cards:
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_0
              name: Speed
            - entity: sensor.sds_task_status_0
              name: Status
            - entity: sensor.sds_task_size_0
              name: Size
            - entity: sensor.sds_task_completed_0
              name: '%'
            - entity: sensor.sds_task_size_downloaded_0
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_0
          icon: 'mdi:numeric-0-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 1 / 2
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_0''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_0
    gridcol: 2 / 3
    gridrow: 1 / 2
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_0
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_0
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 1 / 2
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_1
              name: Speed
            - entity: sensor.sds_task_status_1
              name: Status
            - entity: sensor.sds_task_size_1
              name: Size
            - entity: sensor.sds_task_completed_1
              name: '%'
            - entity: sensor.sds_task_size_downloaded_1
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_1
          icon: 'mdi:numeric-1-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 2 / 3
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_1''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_1
    gridcol: 2 / 3
    gridrow: 2 / 3
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_1
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_1
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 2 / 3
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_2
              name: Speed
            - entity: sensor.sds_task_status_2
              name: Status
            - entity: sensor.sds_task_size_2
              name: Size
            - entity: sensor.sds_task_completed_2
              name: '%'
            - entity: sensor.sds_task_size_downloaded_2
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_2
          icon: 'mdi:numeric-2-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 3 / 4
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_2''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_2
    gridcol: 2 / 3
    gridrow: 3 / 4
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_2
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_2
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 3 / 4
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_3
              name: Speed
            - entity: sensor.sds_task_status_3
              name: Status
            - entity: sensor.sds_task_size_3
              name: Size
            - entity: sensor.sds_task_completed_3
              name: '%'
            - entity: sensor.sds_task_size_downloaded_3
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_3
          icon: 'mdi:numeric-3-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 4 / 5
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_3''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_3
    gridcol: 2 / 3
    gridrow: 4 / 5
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_3
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_3
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 4 / 5
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_4
              name: Speed
            - entity: sensor.sds_task_status_4
              name: Status
            - entity: sensor.sds_task_size_4
              name: Size
            - entity: sensor.sds_task_completed_4
              name: '%'
            - entity: sensor.sds_task_size_downloaded_4
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_4
          icon: 'mdi:numeric-4-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 5 / 6
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_4''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_4
    gridcol: 2 / 3
    gridrow: 5 / 6
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_4
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_4
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 5 / 6
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_5
              name: Speed
            - entity: sensor.sds_task_status_5
              name: Status
            - entity: sensor.sds_task_size_5
              name: Size
            - entity: sensor.sds_task_completed_5
              name: '%'
            - entity: sensor.sds_task_size_downloaded_5
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_5
          icon: 'mdi:numeric-5-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 6 / 7
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_5''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_5
    gridcol: 2 / 3
    gridrow: 6 / 7
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_5
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_5
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 6 / 7
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_6
              name: Speed
            - entity: sensor.sds_task_status_6
              name: Status
            - entity: sensor.sds_task_size_6
              name: Size
            - entity: sensor.sds_task_completed_6
              name: '%'
            - entity: sensor.sds_task_size_downloaded_6
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_6
          icon: 'mdi:numeric-6-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 7 / 8
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_6''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_6
    gridcol: 2 / 3
    gridrow: 7 / 8
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_6
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_6
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 7 / 8
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_7
              name: Speed
            - entity: sensor.sds_task_status_7
              name: Status
            - entity: sensor.sds_task_size_7
              name: Size
            - entity: sensor.sds_task_completed_7
              name: '%'
            - entity: sensor.sds_task_size_downloaded_7
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_7
          icon: 'mdi:numeric-7-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 8 / 9
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_7''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_7
    gridcol: 2 / 3
    gridrow: 8 / 9
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_7
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_7
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 8 / 9
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_8
              name: Speed
            - entity: sensor.sds_task_status_8
              name: Status
            - entity: sensor.sds_task_size_8
              name: Size
            - entity: sensor.sds_task_completed_8
              name: '%'
            - entity: sensor.sds_task_size_downloaded_8
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_8
          icon: 'mdi:numeric-8-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 9 / 10
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_8''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_8
    gridcol: 2 / 3
    gridrow: 9 / 10
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_8
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_8
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 9 / 10
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
  - card:
      entities:
        - entities:
            - entity: sensor.sds_task_speed_down_9
              name: Speed
            - entity: sensor.sds_task_status_9
              name: Status
            - entity: sensor.sds_task_size_9
              name: Size
            - entity: sensor.sds_task_completed_9
              name: '%'
            - entity: sensor.sds_task_size_downloaded_9
              name: Downloaded
          entity: sensor.sds_task_size_downloaded_9
          icon: 'mdi:numeric-9-box'
          name: '${vars[0]}'
          show_state: false
          state_color: true
          type: 'custom:multiple-entity-row'
      gridcol: 1 / 2
      gridrow: 10 / 11
      type: entities
    entities:
      - sensor.sds_tasks_list
    type: 'custom:config-template-card'
    variables:
      - 'states[''sensor.sds_task_name_9''].state'
  - direction: right
    entities:
      - entity: sensor.sds_task_completed_9
    gridcol: 2 / 3
    gridrow: 10 / 11
    height: 35px
    max: 100
    min: 0
    positions:
      icon: 'off'
      indicator: 'off'
      minmax: 'off'
      name: 'off'
      target: 'off'
      value: inside
    severity:
      - color: '#7b55d5'
        from: 0
        to: 25
      - color: '#fc70f3'
        from: 25
        to: 50
      - color: '#00b8fe'
        from: 50
        to: 75
      - color: '#7cff73'
        from: 75
        to: 100
    type: 'custom:bar-card'
  - entities:
      - color: var(--greenish)
        entity: sensor.sds_task_speed_down_9
        name: Download
        state_adaptive_color: true
      - color: var(--light-magenta)
        entity: sensor.sds_task_speed_up_9
        name: Upload
        show_state: true
        state_adaptive_color: true
        y_axis: secondary
    gridcol: 3 / 4
    gridrow: 10 / 11
    height: 150
    hours_to_show: 1
    line_width: 2
    points_per_hour: 360
    show:
      fill: fade
      icon: false
      labels: false
      labels_secondary: false
      legend: false
      name: false
      points: false
      state: false
    type: 'custom:mini-graph-card'
gridcols: 75% auto 170px
gridrows: 80px 80px 80px 80px 80px 80px 80px 80px 80px 80px 80px
layout: grid
type: 'custom:layout-card'

And the final word… I tested this only with torrent downloads, but given the nature of SDS API I’d expect that it should work equally fine with any supported by SDS transfer protocol (BT, FTP/HTTP, NZB, RSS).

Happy downloading!

7 Likes

OK, original solution was not fully satisfactory for me in the end:

  • throwing lots of errors at log due to race conditions between sensors on tasks list change
  • being slow in refresh (REST sensors update only every 30 seconds and more frequent updates makes no sense because of race conditions)
  • causing very frequent re-loggin to SDS/DSM to unnecessarily refresh SID, that additionally could cause issues with sensors updates.
  • if no active task, most of sensors become unavailble, causing potential other issues.

So I decided to take another attemt on this topic and rewrite entire ‘integration’ from scratch. This time I’m using some shell_commands that are controlled by automation, so overal results are way more predictable. I tried to make it in the way, that replacing old download.yaml file with new one should be completely transparrent, in case you created any cards/automations/etc using these sensors (with exception, that all sensors have now clearly defined state under all conditions, so this might break some status change actions).
Regarding installation; it does not changed much; there are few additional step requred, that are highligted in original post, that I edited to mutch current state of this work.
Since I also did not liked much the original card, I created additional, more strimligned view that shows all downloads in form of ‘table’ more like traditional clients view. Installation also is now described in original, update post.

1 Like

Hello, thank you for your work, I will try to try it soon.

Have you planned to make an addon?

Thank you

Well, perhaps one day I’ll learn python and make it addon… For now I have to stick to what I’m capable of :slight_smile:

Hello,

I was going to test your integration but I am missing one point, it is not possible to start or pause all downloads?
Have you planned to integrate a sensor to do this?

thank you

There is Synology API for starting/stopping/deleting individual jobs, though the way I implemented sensors does not allow for easy lining of required script to specific task… I yet need to rethink logic for this, but I’m currently running out of time. Though this is on the list of things to be done, so stay tuned :slight_smile:

Thank you for your reply :slight_smile:

Looks great, will definitely try this in the future.
For this case and other dashboard items I’m working on I was wondering if it’s possible to define a template item like the row for each download task, and generate a new one for each download item dynamically based on certain conditions…

Thanks!
Pieter

Not 100% sure what you want to achieve, but I think you should be doable. I’m not playing with this for some time… drawback is that sensors gets dissynchronized one teh download finishes and it takes few iterations (so up to few minutes) before all download attributes gets in sync again. Also once download is complete some of sensors are updated to show next in order download data while some are still referring to old (finished or shifted in order) task. This might create a lot of errors in the log file. To make it work properly synchronous operation is required, that only can be achieved in proper integration. At the moment sensors are updated in somechow random order and since they depends on each other it might create symtoms as above… For slow downloads (taking a lot of time) it works though like a charm :slight_smile:

I was wondering if there is a way to easily list a number of sensors, or properties of a sensor in your dashboard in a dynamic way.
Can I for example do a for each (download task) > list name, progress, time, start/stop/pause actions, etc?
Without having to write for each (potential task) a seperate line?
At the moment you created 10 tasks for 10 potential downloads.
Could it also work the other way around? so we can fetch however many downloads there are, and that only the necessary rows are being generated that are needed?
I was using the GitHub - N4S4/synology-api: A Python wrapper around Synology API syno api for this in python which works great, but yaml is still not very natural to me :stuck_out_tongue:

Also this would be how I would like to list my 24 server nodes, to keep track of their status, and to be able to power them on/off and perform certain actions on them… they’re all setup in the same way exactly only their ip varies.
So they’re called, node101-124 with ip’s 192.168.1.101-192.168.1.124. Like in python can I run through a list of each of the nodes and generate a button card or something else (each time same makeup) with only the id/ip-name changing.
This way if I make a change or addition all elements are changed.

Thanks!
Pieter

@mirekmal, the code for the entire panelview is not working for me in the latest HA version.
Is it still working for you? If you’ve changed your lovelace yaml, could you update it here aswell?
The yaml works in a way, but it’s not showing the nice horizontal stacked lines. Instead I get 3 columns.

Well, to be honest I removed this from my config as it wat so useful as I hoped :frowning: So I’m not using it for 6~7 months now… What I recall, however, is that custom layout card was quite significantly reworked in meantime (how the grids are defined), so this is most likely the reason… Not having much free time lately, so I cannot promise anything, but maybe I’ll try to look at this and fix to adjust to new setup.