Skip to content

Repository files navigation

hacs_badge GitHub release GitHub repo size

GitHub issues GitHub last commit GitHub commit activity

2dehands Home Assistant integration

2dehands Home Assistant custom component. It provides sensors with info related to your 2dehands account and profile.

It can automatically extend active items that are close to automatic removal when the 2dehands website exposes a callable extension action.

⚠️ Please don't report issues with this integration to 2dehands.be, they will not be able to support you.

Installation

  • HACS: add this repo as a custom repot in HACS and search for the integration in the list of HACS
    • Open your Home Assistant instance and open the repository inside the Home Assistant Community Store.
  • Restart Home Assistant
  • Add '2dehands.be' integration via HA Settings > 'Devices and Services' > 'Integrations'
  • Provide 2dehands.be username and password

Integration

After setup, the integration creates sensors and buttons for your configured 2dehands profile:

Sensor Description
Items being sold Number of active items found in the account.
Favorite items Number of favorite items found on the account favorites page.
Unread messages Number of unread account messages.
Unread notifications Number of unread account notifications.
Extendable items Number of active items where 2dehands exposes the extension link.
Items close to removal Number of active items within the configured extension threshold.

Favorite ads with a recognizable location also create geolocation entities. Their coordinates use location data supplied by 2dehands when available, otherwise the city is matched locally against the bundled GeoNames dataset. The coordinate is therefore the approximate city center, not the seller's address. Favorite city names are not sent to an external geocoding service.

The Items being sold sensor includes attributes for the extension settings, the last extension result, and a sold_items list with item titles, prices, statuses, image URLs, view counts, extension flags, and URLs fetched from https://www.2dehands.be/my-account/sell/api/listings.

The Favorite items sensor includes a favorite_items attribute with favorite item names, prices, statuses, image URLs, locations, and URLs fetched from https://www.2dehands.be/my-account/favorites/favorites.json. The Items close to removal sensor includes an expiring_items attribute with the active items currently inside the extension window. Extension timing uses showExtensionLink, expiring, extensionPending, and closeDate; durationInDays is not used because it describes the listing duration, not the remaining time. When extension is attempted, the integration only calls extension actions discovered from the listing payload or sell overview.

Unread message and notification counts are fetched from https://www.2dehands.be/header/messages/message-count and https://www.2dehands.be/header/notifications/notification-count.

The integration creates a Refresh website data button entity for an immediate manual refresh. Automatic website refreshes remain scheduled every hour. For every own active ad, the integration also creates a Duplicate ... button entity. Pressing this button calls the duplicate service for that source ad and refreshes the integration data afterwards.

Two-factor authentication is detected during setup, but cannot be completed inside Home Assistant.

Favorite ads map

To show all favorite ads on one dashboard map, edit a dashboard, add a Manual card, and paste the following YAML:

type: map
title: Favorite 2dehands ads
aspect_ratio: 16:9
auto_fit: true
hours_to_show: 0
cluster: true
geo_location_sources:
  - 2dehands

The 2dehands geolocation source automatically selects every favorite ad that has a recognized location, so individual entity IDs do not need to be added to the card. New favorites appear automatically and removed favorites disappear after the next integration refresh. Each marker uses the ad's main picture and its entity state contains the advertised price. Markers near each other may be grouped into a cluster; select the cluster to reveal its ads. Ads without a location that can be matched are omitted. Selecting a marker exposes a clickable, absolute url attribute that opens the advertisement on 2dehands. Favorites whose status is Removed are also omitted from the map.

Approximate fallback coordinates are derived from a bundled Belgian/Dutch subset of GeoNames data, licensed under CC BY 4.0.

Services

Following services 2dehands will be available:

  • 2dehands.extend_sales: extend active items which can be extended
    service: 2dehands.extend_sales
    data:
      threshold_days: 3
      force: false

    Optional fields:

    Field Description
    config_entry_id Limit the service call to one configured account. When omitted, all configured accounts are processed.
    threshold_days Extend items when automatic removal is within this many days. Defaults to the integration option.
    force Extend every active item where 2dehands exposes the extension link, even if it is not close to removal yet.
  • 2dehands.duplicate_ad: duplicate one of your own ads
    service: 2dehands.duplicate_ad
    data:
      item_id: m2251423896

    Optional fields:

    Field Description
    config_entry_id Required when multiple 2dehands accounts are configured.
    item_id Item ID of the own ad to copy.

    The service reads the original ad from /seller/view/<item_id>, starts the placement form for the same category and title, uploads copies of the original images, then posts a new free ad to /plaats/ads.

Status

Still some optimisations are planned, see Issues section in GitHub.

Technical pointers

The main logic and API connection related code can be found within source code 2dehands/custom_components/2dehands:

All other files just contain boilerplate code for the integration to work within HA or to have some constants/strings/translations.

Example usage

alias: Extend 2dehands items every morning
trigger:
  - platform: time
    at: "08:00:00"
action:
  - service: 2dehands.extend_sales
    data:
      threshold_days: 3

Dashboard markdown card

The template searches for sensors whose names start with 2dehands, so it also works when Home Assistant adds your account name to the generated entity IDs.

type: markdown
title: 2dehands
content: >
  {% set own_ads_sensors = states.sensor | selectattr('name', 'search',
  '(?i)^2dehands.*items being sold$') | map(attribute='entity_id') | list %}

  {% set favorite_ads_sensors = states.sensor | selectattr('name', 'search',
  '(?i)^2dehands.*favorite items$') | map(attribute='entity_id') | list %}

  {% set unread_messages_sensors = states.sensor | selectattr('name', 'search',
  '(?i)^2dehands.*unread messages$') | map(attribute='entity_id') | list %}

  {% set unread_notifications_sensors = states.sensor | selectattr('name',
  'search', '(?i)^2dehands.*unread notifications$') | map(attribute='entity_id')
  | list %}

  {% set ns = namespace(own_ads=[], favorite_ads=[], unread_messages=0,
  unread_notifications=0) %}

  {% for sensor in own_ads_sensors %}
    {% set ns.own_ads = ns.own_ads + (state_attr(sensor, 'sold_items') or []) %}
  {% endfor %}

  {% for sensor in favorite_ads_sensors %}
    {% set ns.favorite_ads = ns.favorite_ads + (state_attr(sensor, 'favorite_items') or []) %}
  {% endfor %}

  {% for sensor in unread_messages_sensors %}
    {% set ns.unread_messages = ns.unread_messages + (states(sensor) | int(0)) %}
  {% endfor %}

  {% for sensor in unread_notifications_sensors %}
    {% set ns.unread_notifications = ns.unread_notifications + (states(sensor) | int(0)) %}
  {% endfor %}

  {% set own_ads = ns.own_ads %}

  {% set favorite_ads = ns.favorite_ads %}


  **Unread messages:** {{ ns.unread_messages }}<br>

  **Unread notifications:** {{ ns.unread_notifications }}


  <details>
    <summary><strong>Own ads ({{ own_ads | count }})</strong></summary>

  {% if not own_ads_sensors %}

  Own ads sensor not found.

  {% elif own_ads %}

  <ul>

  {% for ad in own_ads %}

  {% set ad_url = ad.url if ad.url and ad.url[:4] == 'http' else
  'https://www.2dehands.be' ~ ad.url if ad.url else '' %}

  {% set title = ad.name or ad.title or 'Ad' %}
    <li>
      <details>
        <summary><strong>{% if ad_url %}<a href="{{ ad_url }}">{{ title | e }}</a>{% else %}{{ title | e }}{% endif %}</strong> - {{ ad.price or 'unknown' }}</summary>
        {% if ad.image_url %}<p><img src="{{ ad.image_url }}" alt="{{ title | e }}" width="96"></p>{% else %}<p></p>{% endif %}
        <ul>
          <li><strong>Price:</strong> {{ ad.price or 'unknown' }}</li>
          <li><strong>Status:</strong> {{ ad.status or 'unknown' }}</li>
          <li><strong>Views:</strong> {{ ad.view_count if ad.view_count is not none else 'unknown' }}</li>
          <li><strong>Needs extension:</strong> {{ 'yes' if ad.needs_extension else 'no' }}</li>
          <li><strong>Can extend:</strong> {{ 'yes' if ad.can_extend else 'no' }}</li>
          {% if ad.expiring %}<li><strong>Expiring:</strong> {{ 'yes' if ad.expiring else 'no' }}</li>
          <li><strong>Extension pending:</strong> {{ 'yes' if ad.extension_pending else 'no' }}</li>
          <li><strong>Expires at:</strong> {{ ad.expires_at or 'unknown' }}</li>{% else %}<p></p>{% endif %}
          <li><strong>Id:</strong> {{ad.item_id }}</li>
        </ul>
      </details>
    </li>
  {% endfor %}

  </ul>

  {% else %}

  No own ads found.

  {% endif %}


  </details>


  <details>
    <summary><strong>Favorite ads ({{ favorite_ads | count }})</strong></summary>

  {% if not favorite_ads_sensors %}

  Favorite ads sensor not found.

  {% elif favorite_ads %}

  <ul>

  {% for ad in favorite_ads %}

  {% set ad_url = ad.url if ad.url and ad.url[:4] == 'http' else
  'https://www.2dehands.be' ~ ad.url if ad.url else '' %}

  {% set title = ad.name or ad.title or 'Ad' %}
    <li>
      <details>
        <summary><strong>{% if ad_url %}<a href="{{ ad_url }}">{{ title | e }}</a>{% else %}{{ title | e }}{% endif %}</strong> - {{ ad.price or 'unknown' }} - {{ ad.status or 'unknown' }}</summary>
        {% if ad.image_url %}<p><img src="{{ ad.image_url }}" alt="{{ title | e }}" width="96"></p>{% endif %}
        <ul>
          <li><strong>Price:</strong> {{ ad.price or 'unknown' }}</li>
          <li><strong>Status:</strong> {{ ad.status or 'unknown' }}</li>
          <li><strong>Location:</strong> {{ ad.location or 'unknown' }}</li>
        </ul>
      </details>
    </li>
  {% endfor %}

  </ul>

  {% else %}

  No favorite ads found.

  {% endif %}


  </details>

Dashboard duplicate buttons

The built-in Home Assistant Markdown card cannot call services from a rendered button. To automatically create a button for every own ad that can be duplicated, install Auto Entities through HACS and add this manual card:

type: custom:auto-entities
card:
  type: grid
  title: Duplicate 2dehands ads
  columns: 2
  square: false
card_param: cards
filter:
  include:
    - domain: button
      entity_id: "button.2dehands*_duplicate_*"
      options:
        type: button
        entity: this.entity_id
        icon: mdi:content-copy
        show_state: false
        tap_action:
          action: perform-action
          perform_action: button.press
          target:
            entity_id: this.entity_id
  exclude:
    - state: unavailable
sort:
  method: name
  ignore_case: true
show_empty: false

The filter acts as the loop: it finds all generated duplicate button entities, including buttons added after a website refresh, and creates one dashboard button for each match. It also supports multiple configured 2dehands accounts. Each button calls 2dehands.duplicate_ad with its matching source item ID.

Without the Auto Entities custom card, add the generated Duplicate ... button entities manually to an Entities card from the dashboard editor.

Use the generated Refresh website data button entity when you want to fetch the latest website data without waiting for the hourly automatic refresh.

type: button
entity: button.2dehands_refresh_website_data
name: Refresh 2dehands
icon: mdi:refresh
tap_action:
  action: perform-action
  perform_action: button.press
  target:
    entity_id: button.2dehands_refresh_website_data

About

Home Assistant Custom Integration (HACS) to provide sensors on your 2dehands.be (2ememain.be) profile and allow some automations on your items sold.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages