Skip to content

Home Assistant Custom integration (HACS) to get information about the public city street parking restrictions (eg costs, parking disc card, parking zone, etc). Currently supported in BE, FR, NL, IT, DE, LU, ES, PT, PL, CZ, AT

License

Notifications You must be signed in to change notification settings

myTselection/CityParking

Repository files navigation

HACS Default GitHub release GitHub repo size

GitHub issues GitHub last commit GitHub commit activity

🅿️ City Parking Home Assistant integration

Home Assistant custom integration to provide public street city parking information for any location. This custom component has been built from the ground up to fetch public parking information and integrate this information into Home Assistant. This integration is built against the public websites provided by seety.co and seety Maps. (and maybe other similar sites such as Parkopedia in future). Sensors will be created for any desired location and specific service can be called to get parking information ad hoc of any location.

This integration is in no way affiliated with seety.

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

Main use case

Whenever you exit your car (and while not at home), check if any public city parking limitations apply for your current location. Warn you when you need to place your parking disk or show local parking rates.

To detect exiting a car, an automation can be defined using sensor.smartphone_ha_activity changing from 'Automotive', or an iOS shortcut can be used to trigger when CarPlay is disconnected and a webhook request can be launched to Home Assistant to trigger an action.

Installation

  • HACS: search for CityParking in the default HACS repo list or use below button to navigate directly to it on your local system and install via HACS.
    • Open your Home Assistant instance and open the repository inside the Home Assistant Community Store.
  • Restart Home Assistant
  • Add 'City Parking' integration via HA Settings > 'Devices and Services' > 'Integrations'
  • In the setup configuration, provide an origin.
    • This can be any HA sensor which has latitutde and longitude attributes (eg person.jef, device_tracker.car, etc).

      You can also provide latitude and longitude information, eg 51.3304,3.802.

      You can also just provide the full address (but I noticed the current pywaze convertion from address to lat/lon is not very accurate).

Integration

Sensors

  • sensor.parking_[origin]_address: sensor with adres linked to location of origin

  • sensor.parking_[origin]_days_restrictions: sensor with indication of days on which the city parking is restricted

  • sensor.parking_[origin]_max_stay: sensor with max amount of minutes is allowed to park during the days and time restricted schedule

  • sensor.parking_[origin]_price: sensor with price info for the city parking

  • sensor.parking_[origin]_remarks: sensor with remarks related to the the city parking

  • sensor.parking_[origin]_restriction_active: sensor with indication if the time and day restrictions are currenlty active. Eg if Sunday the city parking is not restricted, the restricted_active sensor will be False

  • sensor.parking_[origin]_time_restrictions: sensor with indication of time schedule duding which the city parking is restricted

  • sensor.parking_[origin]_type: sensor with type of city parking zone (eg disk, paid, free, etc)

  • sensor.parking_[origin]_zone: sensor with zone name of the city parking (eg green, yellow, orange, red, blue, etc)

  • Sensor data will be updated every 5min, unless the coordinates of the origin didn't change. The attribute time_restriction_active_now, day_restriction_active_now, maxstay_* and restriction_active will always be updated every 5min. These indicate if the restrictions currently apply.

  • For now all sensors have the same set of attributes
    Attribute Description
    State zone
    origin Original origin provided during setup of the sensor
    latitude Latitude of the origin
    longitude Longitude of the origin
    url Seety.co url to the addresss
    type Type of the public parking, eg paid
    time_restrictions Time restrictions for the public parking
    days_restrictions Days at which the public parking is limited
    prices Price indication for 1 or 2 hours parking and amount of free parking allowed
    remarkds Extra info related to the public parking
    max_stay Max time you can stay at the public parking
    zone Name of the zone, blue/orange/red zone indication of public parking
    address Address for which the parking information is shown
    time_restriction_active_now Time restrictions are currently active
    day_restriction_active_now Day restrictions are currently active
    maxstay_passed_now Max stay has passed
    maxstay_elapsed Time (min) elapsed since max stay started
    maxstay_remaining Time (min) remaining until max stay is reached
    maxstay_start_time Time at which max stay started
    restriction_active Time and day restrictions are currently active
    last_update Last time data was updated
    last_restriction_check Last time restrictions were checked
    attribution Attribution for the data
    device_class Device class
    icon Icon to display
    friendly_name Friendly name for the sensor

Services / Actions / Automation

  • Get notified when you stopped driving about public city parking restrictions that may apply:

    • Example automation script
      alias: Parking Notification
      description: ""
      triggers:
      - trigger: state
        entity_id:
          - sensor.smartphone_ha_activity
        from:
          - Automotive
        for:
          hours: 0
          minutes: 0
          seconds: 30
      - trigger: webhook
        allowed_methods:
          - POST
          - PUT
        local_only: true
        webhook_id: "cityparking"
      conditions:
      - condition: not
        conditions:
          - condition: zone
            entity_id: person.jef
            zone: zone.home
      actions:
      - action: script.parking_notification
        metadata: {}
        enabled: true
      mode: single
      
      
    • Example parking_notification script. Generic script with actionable notification
      alias: Parking Notification
      description: "Interactive parking notification, if 'source_sensor' var is set, the parking info of that sensor will be used, else the parking info of person.name will be fetched."
      icon: mdi:parking
      sequence:
        - if:
            - condition: template
              value_template: "{{ source_sensor != unavailable}}"
          then:
            - variables:
                extra_data:
                  zone: "{{state_attr(source_sensor, 'zone')}}"
                  type: "{{state_attr(source_sensor, 'type')}}"
                  restriction_active: "{{state_attr(source_sensor, 'restriction_active')}}"
                  address: "{{state_attr(source_sensor, 'address')}}"
                  days_restrictions: "{{state_attr(source_sensor, 'days_restrictions')}}"
                  time_restrictions: "{{state_attr(source_sensor, 'time_restrictions')}}"
                  price: "{{state_attr(source_sensor, 'price')}}"
                  remarks: "{{state_attr(source_sensor, 'remarks')}}"
                  url: "{{state_attr(source_sensor, 'url')}}"
          else:
            - action: cityparking.city_parking_info
              metadata: {}
              data:
                origin: person.name
              response_variable: parking_info
            - variables:
                 extra_data:
                   zone: "{{parking_info.city_parking_info.extra_data.zone}}"
                   type: "{{parking_info.city_parking_info.extra_data.type}}"
                   restriction_active: "{{parking_info.city_parking_info.extra_data.restriction_active}}"
                   address: "{{parking_info.city_parking_info.extra_data.address}}"
                   days_restrictions: "{{parking_info.city_parking_info.extra_data.days_restrictions}}"
                   time_restrictions: "{{parking_info.city_parking_info.extra_data.time_restrictions}}"
                   price: "{{parking_info.city_parking_info.extra_data.price}}"
                   remarks: "{{parking_info.city_parking_info.extra_data.remarks}}"
                   url: "{{parking_info.city_parking_info.extra_data.url}}"
        - variables:
            critical_desired: >-
              {% if states('sensor.smartphone_ha_activity') == 'Automotive' or 
              (trigger is defined and trigger.event is defined and
              trigger.event.data.triggerSource == 'carPlay') %}1{% else %}0{% endif %}
            notification_tag: parking
            title: >-
              🅿️ {{extra_data.zone}} ({{extra_data.type}}) Active:
              {{extra_data.restriction_active}}
            message: >-
              {{extra_data.type}} ({{extra_data.zone}}): {{extra_data.address}}
      
              {% if extra_data.restriction_active %}⚠️{% endif %}Restricted on:
              {{extra_data.days_restrictions}}, between
              {{extra_data.time_restrictions}}
      
              Price: {{extra_data.price}}
      
              Remarks: {{extra_data.remarks}}
            actions_uri:
              - action: URI
                title: Map parking 🅿️
                uri: "{{extra_data.url}}"
                activationMode: background
                authenticationRequired: true
                destructive: false
                behavior: default
            action_map_car:
              - action: map_car
                title: Map car 🗺️
                activationMode: background
                authenticationRequired: true
                destructive: false
                behavior: default
            action_map_traffic:
              - action: map_traffic
                title: Map traffic 🛣️
                activationMode: background
                authenticationRequired: true
                destructive: false
                behavior: default
            action_refresh_car_data:
              - action: refresh_car_data
                title: Refresh car data 🔄️
                activationMode: background
                authenticationRequired: true
                destructive: false
                behavior: default
            actions_desired: >-
              {{actions_uri + action_map_car + action_map_traffic + action_refresh_car_data}}
        - choose: []
          default:
            - continue_on_error: true
              data:
                title: "{{title}}"
                message: "{{message}}"
                data:
                  push:
                    sound:
                      name: default
                      critical: "{{critical_desired}}"
                  url: "{{extra_data.url}}"
                  group: "{{notification_tag}}"
                  tag: "{{notification_tag}}"
                  action_data:
                    latitude: "{{state_attr('person.car','latitude')}}"
                    longitude: "{{state_attr('person.car','longitude')}}"
                    second_latitude: "{{extra_data.latitude}}"
                    second_longitude: "{{extra_data.longitude}}"
                  actions: "{{actions_desired}}"
              action: notify.notify
            - wait_for_trigger:
                - event_type: mobile_app_notification_action
                  trigger: event
              timeout:
                hours: 0
                minutes: 0
                seconds: 30
                milliseconds: 0
              continue_on_timeout: true
              enabled: true
            - choose:
                - conditions:
                    - condition: template
                      value_template: "{{wait.trigger == None}}"
                  sequence:
                     - continue_on_error: true
                       data:
                         title: "{{title}}"
                         message: "{{message}}"
                         data:
                           push:
                             sound:
                               name: default
                               critical: "{{critical_desired}}"
                           url: "{{extra_data.url}}"
                           group: "{{notification_tag}}"
                           tag: "{{notification_tag}}"
                           action_data:
                             latitude: "{{state_attr('person.car','latitude')}}"
                             longitude: "{{state_attr('person.car','longitude')}}"
                             second_latitude: "{{extra_data.latitude}}"
                             second_longitude: "{{extra_data.longitude}}"
                       action: notify.notify
                     - stop: timeout
            - variables:
                option: "{{ wait.trigger.event.data.action }}"
                selected_entity: |
                  {{
                    {'map_traffic': 'automation.traffic_notificaiton',
                     'map_car': 'person.car',
                     'refresh_car_data': 'script.refresh_car_data'
                     }[wait.trigger.event.data.action] }}
                entity_type: "{{selected_entity.split('.')[0] }}"
            - choose:
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'sensor' or entity_type == 'person' }}"
                  sequence:
                    - data:
                        message: >-
                          {{option}}: {{state_attr(selected_entity,'thoroughfare')}}
                          {{state_attr(selected_entity,'sub_thoroughfare')}},
                          {{state_attr(selected_entity,'locality')}}
                        data:
                          push:
                            sound:
                              name: default
                              critical: "{{critical_desired}}"
                          group: person
                          tag: person
                          action_data:
                            latitude: "{{state_attr('person.car','latitude')}}"
                            longitude: "{{state_attr('person.car','longitude')}}"
                            second_latitude: "{{extra_data.latitude}}"
                            second_longitude: "{{extra_data.longitude}}"
                          url: /lovelace/parking
                      action: notify.notify
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'light' }}"
                  sequence:
                    - data: {}
                      target:
                        entity_id: "{{selected_entity}}"
                      action: light.toggle
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'switch' }}"
                  sequence:
                    - data: {}
                      target:
                        entity_id: "{{selected_entity}}"
                      action: switch.toggle
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'script' }}"
                  sequence:
                    - data: {}
                      target:
                        entity_id: "{{selected_entity}}"
                      action: script.turn_on
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'automation' }}"
                  sequence:
                    - data:
                        skip_condition: true
                      target:
                        entity_id: "{{selected_entity}}"
                      action: automation.trigger
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'lock' }}"
                  sequence:
                    - data: {}
                      target:
                        entity_id: "{{selected_entity}}"
                      action: lock.lock
                - conditions:
                    - condition: template
                      value_template: "{{ entity_type == 'unlock' }}"
                  sequence:
                    - data: {}
                      target:
                        entity_id: "{{selected_entity|replace('unlock', 'lock')}}"
                      action: lock.unlock
      
      
  • Find the public parking information to a given location.

    • Service find nearest

    • The response will contain all available seety.co data. On top, a dict extra_data is available which contains the most relevant data as used in the 'City Parking' sensors.

    • It will return a JSON such as example below:
      
      city_parking_info:
        user:
          user:
            verified: false
            cars: []
            mustSendMailOnEachTransaction: true
            proAccountActivated: false
            subscribedToOnboardingCampaign: true
            time: "2026-01-28T22:03:31.214000+00:00"
            lastSeen: "2026-01-28T22:03:31.214000+00:00"
            confidence: 0
            lang: en
          lastMapUpdate: "2024-11-20T23:00:00"
          remoteConfigsLastUpdate:
            messages: "2025-01-16"
          access_token: >-
            <token>
          expires_in: 10800
          refresh_token: >-
            <token>
          status: OK
        location:
          status: OK
          results:
            - formatted_address: Raadhuisstraat 11, 1016 DB Amsterdam
              countryCode: NL
              geometry:
                location:
                  lat: 52.37315
                  lng: 4.890025
              types:
                - street_address
        rules:
          rules:
            days:
              - 0
              - 1
              - 2
              - 3
              - 4
              - 5
              - 6
            prices:
              "0": 0
              "1": 1.7
              "2": 3.3
            hours:
              - "00:00"
              - "06:00"
            type: paid
            paymentPartner: shpv
            advantageInApp: false
            displayNotPayable: false
            overrides: {}
            forceDisplayPriceTables: false
          risk: 0
          overrides: {}
          properties:
            type: orange-1
            color: "#ff6a00"
            dotted: false
            closest:
              - 4.89029214636468
              - 52.37323057359693
            closestDist: 0.010858118135837055
            maxDistToPay: 0.01
            city: amsterdam
          twoSided: false
          status: OK
        streetComplete:
          rules:
            yellow:
              weight: 4.2
              summary:
                days:
                  - 0
                  - 1
                  - 2
                  - 3
                  - 4
                  - 5
                  - 6
                prices:
                  "0": 0
                  "1": 1.7
                  "2": 3.3
                hours:
                  - "09:00"
                  - "19:00"
                type: paid
                paymentPartner: shpv
                advantageInApp: false
                displayNotPayable: false
                overrides: {}
                forceDisplayPriceTables: false
              remarks:
                - "Fine: 150€."
              specialPermits:
                residents: []
                disabled: []
              maxStay: "600"
              color:
                color: "#ffdd00"
                dotted: false
              name: Yellow zone
              table:
                - rows:
                    09:00,19:00:
                      - 0.4
                      - 0.9
                      - 1.7
                      - 3.4
                      - 5.2
                      - 6.9
                      - 8.6
                      - 10.3
                      - 10.3
                  cols:
                    - "15"
                    - "30"
                    - "60"
                    - "120"
                    - "180"
                    - "240"
                    - "300"
                    - "360"
                    - "600"
                  days:
                    - 0
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                  accessHours: {}
                  entryHours: null
              parkingPaymentProviders:
                - seety_nl
                - 4411_nl
                - driveulu_nl
                - ease2pay_nl
                - easypark_nl
                - lekkerparkeren_nl
                - mkbbrandstof_nl
                - parkd_nl
                - parkline_nl
                - parkmobile_nl
                - parksen_nl
                - paybyphone_nl
                - qpark_nl
                - sms_parking_nl
                - tanqyou_nl
                - yellowbrick_nl
              displayNotPayable: false
            yellow-10:
              weight: 4.2
              summary:
                days:
                  - 1
                  - 2
                  - 3
                  - 4
                  - 5
                  - 6
                prices:
                  "0": 0
                  "1": 1.2
                  "2": 2.5
                hours:
                  - "10:00"
                  - "20:00"
                type: paid
                paymentPartner: shpv
                advantageInApp: false
                displayNotPayable: false
                overrides: {}
                forceDisplayPriceTables: false
              remarks:
                - "Fine: 150€."
              specialPermits:
                residents: []
                disabled: []
              maxStay: "600"
              color:
                color: "#ffdd00"
                dotted: false
              name: Yellow zone 10
              table:
                - rows:
                    09:00,19:00:
                      - 0.1
                      - 0.1
                      - 0.2
                      - 0.3
                      - 2
                      - 3.7
                      - 5.5
                      - 7.2
                      - 8.9
                      - 10.3
                      - 10.3
                  cols:
                    - "15"
                    - "60"
                    - "120"
                    - "180"
                    - "240"
                    - "300"
                    - "360"
                    - "420"
                    - "480"
                    - "540"
                    - "600"
                  days:
                    - 0
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                  accessHours: {}
                  entryHours: null
              parkingPaymentProviders:
                - seety_nl
                - 4411_nl
                - driveulu_nl
                - ease2pay_nl
                - easypark_nl
                - lekkerparkeren_nl
                - mkbbrandstof_nl
                - parkd_nl
                - parkline_nl
                - parkmobile_nl
                - parksen_nl
                - paybyphone_nl
                - qpark_nl
                - sms_parking_nl
                - tanqyou_nl
                - yellowbrick_nl
              displayNotPayable: false
            orange-3:
              weight: 5.3
              summary:
                days:
                  - 0
                  - 1
                  - 2
                  - 3
                  - 4
                  - 5
                  - 6
                prices:
                  "0": 0
                  "1": 5.2
                  "2": 10.4
                hours:
                  - "00:00"
                  - "24:00"
                type: paid
                paymentPartner: shpv
                advantageInApp: false
                displayNotPayable: false
                overrides: {}
                forceDisplayPriceTables: false
              remarks:
                - "Fine: 150€."
              specialPermits:
                residents: []
                disabled: []
              maxStay: "1440"
              color:
                color: "#ff6a00"
                dotted: false
              name: Orange zone 3
              table:
                - rows:
                    19:00,24:00:
                      - 0.4
                      - 0.9
                      - 1.7
                      - 3.4
                      - 5.2
                      - 6.8
                      - 10.3
                      - 12
                      - 13.6
                      - 18.9
                      - 20.4
                      - 27.2
                      - 34
                      - 34
                  cols:
                    - "15"
                    - "30"
                    - "60"
                    - "120"
                    - "180"
                    - "240"
                    - "360"
                    - "420"
                    - "480"
                    - "660"
                    - "720"
                    - "960"
                    - "1260"
                    - "1440"
                  days:
                    - 0
                  accessHours: {}
                  entryHours: null
                - rows:
                    00:00,06:00:
                      - 0.4
                      - 0.9
                      - 1.7
                      - 3.4
                      - 5.2
                      - 6.9
                      - 8.6
                      - 10.3
                      - 12
                      - 13.8
                      - 15.5
                      - 17.2
                      - 18.9
                      - 20.6
                      - 22.4
                      - 24.1
                      - 25.8
                      - 27.5
                      - 29.2
                      - 31
                      - 32.7
                      - 34.4
                      - 36.1
                      - 37.8
                      - 39.6
                      - 41.3
                  cols:
                    - "15"
                    - "30"
                    - "60"
                    - "120"
                    - "180"
                    - "240"
                    - "300"
                    - "360"
                    - "420"
                    - "480"
                    - "540"
                    - "600"
                    - "660"
                    - "720"
                    - "780"
                    - "840"
                    - "900"
                    - "960"
                    - "1020"
                    - "1080"
                    - "1140"
                    - "1200"
                    - "1260"
                    - "1320"
                    - "1380"
                    - "1440"
                  days:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                  accessHours: {}
                  entryHours: null
              parkingPaymentProviders:
                - seety_nl
                - 4411_nl
                - driveulu_nl
                - ease2pay_nl
                - easypark_nl
                - lekkerparkeren_nl
                - mkbbrandstof_nl
                - parkd_nl
                - parkline_nl
                - parkmobile_nl
                - parksen_nl
                - paybyphone_nl
                - qpark_nl
                - sms_parking_nl
                - tanqyou_nl
                - yellowbrick_nl
              displayNotPayable: false
            noparking:
              weight: 0
              summary:
                days:
                  - 0
                  - 1
                  - 2
                  - 3
                  - 4
                  - 5
                  - 6
                prices:
                  "0": 0
                hours:
                  - "00:00"
                  - "24:00"
                type: noparking
                paymentPartner: null
                advantageInApp: false
                displayNotPayable: false
                overrides: {}
                forceDisplayPriceTables: false
              remarks: []
              specialPermits:
                residents: []
                disabled: []
              maxStay: 0
              color:
                color: "#000000"
                dotted: true
              name: Black dotted zone
              table:
                - rows:
                    00:00,24:00: []
                  cols: []
                  days:
                    - 0
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                  accessHours: {}
                  entryHours: null
              parkingPaymentProviders: []
              displayNotPayable: false
            red:
              weight: 6.2
              summary:
                days:
                  - 0
                  - 1
                  - 2
                  - 3
                  - 4
                  - 5
                  - 6
                prices:
                  "0": 0
                  "1": 5.2
                  "2": 10.4
                hours:
                  - "09:00"
                  - "24:00"
                type: paid
                paymentPartner: shpv
                advantageInApp: false
                displayNotPayable: false
                overrides: {}
                forceDisplayPriceTables: false
              remarks:
                - "Fine: 150€."
              specialPermits:
                residents: []
                disabled: []
              maxStay: "600"
              color:
                color: "#ff0000"
                dotted: false
              name: Red zone
              table:
                - rows:
                    09:00,19:00:
                      - 25.1
                      - 25.1
                      - 25.1
                  cols:
                    - "15"
                    - "60"
                    - "600"
                  days:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                    - 6
                  accessHours: {}
                  entryHours: null
              parkingPaymentProviders:
                - seety_nl
                - 4411_nl
                - driveulu_nl
                - ease2pay_nl
                - easypark_nl
                - lekkerparkeren_nl
                - mkbbrandstof_nl
                - parkd_nl
                - parkline_nl
                - parkmobile_nl
                - parksen_nl
                - paybyphone_nl
                - qpark_nl
                - sms_parking_nl
                - tanqyou_nl
                - yellowbrick_nl
              displayNotPayable: false
          table:
            - rows:
                00:00,24:00:
                  - 2
                  - 4
                  - 8.1
                  - 16.1
                  - 24.2
                  - 32.2
                  - 40.3
                  - 48.3
                  - 56.4
                  - 64.4
                  - 72.5
                  - 80.5
                  - 88.6
                  - 96.6
                  - 104.7
                  - 112.7
                  - 120.8
                  - 128.8
                  - 136.9
                  - 144.9
                  - 153
                  - 161
                  - 169.1
                  - 177.1
                  - 185.2
                  - 193.2
              cols:
                - "15"
                - "30"
                - "60"
                - "120"
                - "180"
                - "240"
                - "300"
                - "360"
                - "420"
                - "480"
                - "540"
                - "600"
                - "660"
                - "720"
                - "780"
                - "840"
                - "900"
                - "960"
                - "1020"
                - "1080"
                - "1140"
                - "1200"
                - "1260"
                - "1320"
                - "1380"
                - "1440"
              days:
                - 0
                - 1
                - 2
                - 3
                - 4
                - 5
                - 6
              accessHours: {}
              entryHours: null
          maxStay: "1440"
          remarks:
            - "Fine: 150€."
          specialPermits:
            residents: []
            disabled: []
          providers:
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment: null
                  fixed: 0.35
                  percentage: null
                sessionSubscription: null
                notifSms:
                  comment: null
                  fixed: 0.15
                  percentage: null
                notifApp: null
              advantageApp:
                fr:
                  - >-
                    Il n'est pas nécessaire de sélectionner une durée spécifique
                    (start & stop)
                  - Disponible dans plus de 150 villes belges
                  - Inscription plutôt facile
                en:
                  - Not necessary to select a specific duration (start & stop)
                  - Available in more than 60 Belgian cities
                  - Registration rather  easy
                nl:
                  - >-
                    Het is niet nodig om een specifieke duur te selecteren (start &
                    stop)
                  - Beschikbaar in meer dan 60 Belgische steden
                  - Inschrijving eerder eenvoudig
              disadvantageApp:
                fr:
                  - Relativement cher
                  - >-
                    Dans certains cas, il faut se rendre à l'horodateur pour avoir le
                    code de la zone
                  - Attention aux notifications payantes
                  - Inscription obligatoire avant de découvrir l'app
                  - Nombre de parkings publics limité
                en:
                  - Relatively expensive
                  - >-
                    In some cases, you have to go to the parcmeter to get the code of
                    the zone
                  - Beware of paid notifications
                  - Registration required before discovering the app
                  - Limited number of public parkings
                nl:
                  - Relatief duur
                  - >-
                    In sommige gevallen moet u naar de parkeermeter gaan om de code
                    voor de zone te krijgen
                  - Pas op voor meldingen die betalend zijn
                  - Inschrijving vereist voor het ontdekken van de app
                  - Beperkt aantal openbare parkings
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: "4411"
              intName: 4411_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/4411.png
              subscriptions: []
              url: www.4411.io
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: "0"
              subscriptionType: null
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment:
                    fr: Hors TVA
                    en: Exclusive of VAT
                    nl: Exclusief BTW
                  fixed: 0.3
                  percentage: null
                sessionSubscription:
                  comment: null
                  fixed: 0
                  percentage: null
                notifSms:
                  comment: null
                  fixed: 0.25
                  percentage: null
                notifApp: null
              advantageApp:
                fr:
                  - >-
                    Inclus un système de navigation (mais très limité par rapport  à
                    Google maps ou Waze)
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - Inscription obligatoire avant de découvrir l'app
                  - >-
                    Obligation d'avoir une plaque de voiture valide pour accéder à
                    l'application
                  - Relativement cher
                  - Peu d'explications sur le fonctionnement de la carte
                  - Le design et l'expérience utilisateur pourraient être amélioré
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: Drive ULU
              intName: driveulu_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/drive-ulu.jpg
              subscriptions: []
              url: www.driveulu.com
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment: null
                  fixed: 0.19
                  percentage: null
                sessionSubscription:
                  comment: null
                  fixed: 0
                  percentage: null
                notifSms:
                  comment:
                    fr: Commentaire en FR
                    en: Commentaire en EN
                    nl: Commentaire en NL
                  fixed: 0
                  percentage: null
                notifApp: null
              advantageApp:
                fr:
                  - Disponible dans plus de 140 villes aux Pays-Bas
                  - Frais de transaction raisonnable si vous  rechargez du crédit
                  - >-
                    Possibilité de payer son parking sans devoir créer de compte (mais
                    dans ce cas les frais de transactions sont beaucoup plus chers
                    (0,35€)
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - Application peu intuitive
                  - >-
                    Si vous n'utilisez par leur système de crédit, les frais de
                    transactions sont très chers (0,25€ avec iDEAL et 0,35€ avec une
                    carte de crédit)
                  - >-
                    Vous devez définir à l'avance combien de temps vous voulez rester
                    stationné
                  - >-
                    Pas d'informations dans les zones où le paiement du parking n'est
                    pas disponible
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: Easy2pay
              intName: ease2pay_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/ease2pay.png
              subscriptions:
                - period: 7
                  price: 0.49
                - period: 30
                  price: 1.49
                - period: 365
                  price: 14.99
              url: http://www.ease2pay.nl/
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment:
                    fr: Min. 29cts.
                    en: Min. 29cts.
                    nl: Min. 29cts.
                  fixed: null
                  percentage: 15
                sessionSubscription: null
                notifSms: null
                notifApp: null
              advantageApp:
                fr:
                  - Choix de la zone relativement aisé
                  - Inscription relativement facile
                  - Possibilité de payer son stationnement dans des parking publics
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - Une des applications la plus chère du marché
                  - Attention aux notifications payantes
                  - Obligé de choisir une durée de stationnement prédéfinie
                  - Inscription obligatoire avant de découvrir l'app
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: EasyPark
              intName: easypark_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/easypark.png
              subscriptions:
                - period: 30
                  price: 1.99
              url: www.easyparknederland.nl
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment: null
                  fixed: 0.22
                  percentage: null
                sessionSubscription:
                  comment: null
                  fixed: 0
                  percentage: null
                notifSms: null
                notifApp: null
              advantageApp:
                fr:
                  - >-
                    Notifications gratuites pour vous rappelez qu'une session est en
                    cours
                  - Vous pouvez ajouter autant de plaque que vous le désirez
                  - Disponible dans plus de 100 villes aux Pays-bas
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - Frais de transaction relativement cher
                  - Le design et l'expérience utilisateur pourraient être amélioré
                  - Application uniquement disponible aux Pays-Bas
                  - Inscription obligatoire afin de découvrir l'app
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: LekkerParkeren
              intName: lekkerparkeren_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/lekker-parkeren.png
              subscriptions:
                - period: 30
                  price: 1.99
              url: http://www.lekkerparkeren.nl/
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
            - descriptionApp:
                fr: "<div class=\"prices\">\n        <h3>Tarifs</h3>\n        <ul>\n \t<li>Frais de transaction de 0.15€ (les moins chers)</li>\n\t<li>Frais d'activation : 0€</li>\n\t<li>Frais de notification dans l'app : gratuit </li>\n\t<li>Moyens de paiements acceptés (Carte de crédit, Domiciliation, Apple et Google Pay)</li>\n</ul></div>"
                en: "<div class=\"prices\">\n        <h3>Rates</h3>\n        <ul>\n \t<li>Transaction fee of 0.15€ (least expensive)</li>\n\t<li>Activation fee: 0€</li>\n\t<li>Notification fee in the app: free</li>\n\t<li>Accepted payment methods (Credit Card, domiciliation, Apple and Google Pay)</li>\n</ul></div>"
                nl: "<div class=\"prices\">\n        <h3>Tarieven</h3>\n        <ul>\n \t<li>Transactiekosten van 0.15€ (goedkoopste)</li>\n\t<li>Activeringskosten: 0€</li>\n\t<li>Notificatiekost in de app: gratis</li>\n\t<li>Betaalmiddelen (kredietkaart, domiciliering, Apple en Google Pay)</li>\n</ul></div>"
              descriptionSMS: null
              fees:
                registration:
                  fixed: 0
                session:
                  comment: null
                  fixed: 0.19
                  percentage: null
                sessionSubscription: null
                notifSms: null
                notifApp: null
              advantageApp:
                fr:
                  - >-
                    L'app vous aide à trouver les zones de stationnement gratuites ou
                    les moins chères
                  - Seety est l'app la moins chère pour payer son parking au Pays-Bas
                  - Frais de transaction les plus bas du marché
                  - L'app la plus intuitive (inscription rapide, facile et sécurisée)
                  - Propose automatiquement la zone la plus proche
                  - >-
                    Il n'est pas nécessaire de sélectionner une durée spécifique
                    (start & stop)
                  - >-
                    Notifications intelligentes gratuites pour éviter les mauvaises
                    surprises
                  - Recevez gratuitement une facture mensuelle pour les professionnels
                  - >-
                    Possibilité de réserver un grand nombre de parkings publics via
                    l'app
                  - Disponible partout aux Pays-Bas et en Belgique
                  - Support client 5 étoiles
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - Payement du parking en rue pas encore disponible en France
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: Seety
              intName: seety_nl
              rating: 4.9
              logo: https://storage.googleapis.com/cpark-static-images/seety.png
              subscriptions: []
              url: https://seety.page.link/Kdp9
              transactionPrice: "0.15"
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
            - descriptionApp: null
              descriptionSMS: null
              fees:
                registration:
                  fixed: 5
                session:
                  comment: null
                  fixed: 0.34
                  percentage: null
                sessionSubscription:
                  comment:
                    fr: Abonnement flex. Min 0,15€, max 0,50€.
                    en: Flex subscription. Min 0,15€, max 0,50€.
                    nl: Flex abonnement. Min 0,15€, max 0,50€.
                  fixed: 0.15
                  percentage: null
                notifSms:
                  comment: null
                  fixed: 0.35
                  percentage: null
                notifApp: null
              advantageApp:
                fr:
                  - Possibilité d'ajouter certaines zones en favoris
                  - Présentation des différents horodateurs à proximité
                en: []
                nl: []
              disadvantageApp:
                fr:
                  - >-
                    Vous devez payer 2,5€ chaque fois que vous voulez rajouter une
                    plaque d'immatriculation
                  - Une des applications la plus chère du marché
                  - Inscription obligatoire avant de découvrir l'app
                  - Uniquement disponible pour le parking en rue
                  - Inscription relativement longue
                en: []
                nl: []
              advantageSms:
                fr: []
                en: []
                nl: []
              disadvantageSms:
                fr: []
                en: []
                nl: []
              name: Yellowbrick
              intName: yellowbrick_nl
              rating: 4
              logo: >-
                https://storage.googleapis.com/cpark-static-images/mobility-providers/yellowbrick.png
              subscriptions:
                - period: 7
                  price: 0.75
              url: https://www.yellowbrick.nl/
              transactionPrice: null
              notificationPrice: "0"
              registrationFees: "0"
              subscriptionPrice: null
              subscriptionType: null
          city:
            fr: Amsterdam
            en: Amsterdam
            nl: Amsterdam
          cityName: Amsterdam
          status: OK
        origin: zone.home
        origin_coordinates:
          lat: 52.3731339
          lon: 4.8903147
          bounds: {}
        extra_data:
          origin: zone.home
          latitude: 52.3731339
          longitude: 4.8903147
          type: paid
          time_restrictions:
            - "00:00"
            - "06:00"
          days_restrictions: 7d/7
          prices: 1.7€ (1h) - 3.3€ (2h)
          remarks: "Fine: 150€."
          maxStay: 24h
          zone: orange 🟠
          address: Raadhuisstraat 11, 1016 DB Amsterdam, NL
          url: https://map.seety.co/Raadhuisstraat 11, 1016 DB Amsterdam, NL/16?lang=en
          type_src: "paid"
          time_restrictions_src: ["00:00", "06:00"]
          days_restrictions_src: [0,1,2,3,4,5,6]
          price_src: {1: 1,7, 2: 3.3}
          remarks_src: ["Fine: 150€"]
          max_stay_src: 1440
          zone_src: orange-2
          address_src: Raadhuisstraat 11, 1016 DB Amsterdam
          time_restriction_active_now: false
          day_restriction_active_now: false
          maxstay_passed_now: false
          maxstay_elapsed: 0
          maxstay_remaining: 0
          maxstay_start_time: "2026-02-08T12:54:59.578763+01:00"
          restriction_active: false
          last_update: "2026-02-08T12:54:59.578763+01:00"
          last_restriction_check: "2026-02-08T12:54:59.578770+01:00"
      
      
      

Markdown example

Markdown card. Below example has a condition to only be visible is some parking restiction would apply.

Replace sensor.parking_person_car_restriction_active with the name of your own parking sensor.

Translation of type is optional.


type: markdown
content: >
  {% set source_sensor = 'sensor.parking_person_car_restriction_active' %}
  {% set zone = state_attr(source_sensor, 'zone') %}
  {% set type = state_attr(source_sensor, 'type') %}
  {% set restriction_active = state_attr(source_sensor, 'restriction_active') %}
  {% set address = state_attr(source_sensor, 'address') %}
  {% set days_restrictions = state_attr(source_sensor, 'days_restrictions') %}
  {% set time_restrictions = state_attr(source_sensor, 'time_restrictions') %}
  {% set price = state_attr(source_sensor, 'price') %}
  {% set remarks = state_attr(source_sensor, 'remarks_src') | list %}
  {% set url = state_attr(source_sensor, 'url') %}

  {% set translations = {
    'free': 'Gratis',
    'paid': 'Betalend',
    'disc': 'Blauwe schijf',
    'Unknown': ''
  } %}



  <a href='{{ url }}'>🅿️ {{zone}}: {{translations.get(type, '')}}</a>

  🚘 {{address}}

  {% if restriction_active == 'True' %}⚠️ {% endif %}Restricted on: {{days_restrictions}},
  between {{time_restrictions}}

  {% if price %}💶 Price: {{price}}{% endif %}

  {% if remarks %} <details><summary><b>Remarks:</b></summary>

  {% for remark in remarks %}  

  - {{ remark }}  {% endfor %}  

  </details> {% endif %}
visibility:
  - condition: state
    entity: sensor.parking_person_car_restriction_active
    state: "True"

Status

Proof of concept status, still validating and extending functionalities. Issues section in GitHub.

Technical pointers

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

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

If you would encounter some issues with this custom component, you can enable extra debug logging by adding below into your configuration.yaml:

logger:
  default: info
  logs:
     custom_components.cityparking: debug

About

Home Assistant Custom integration (HACS) to get information about the public city street parking restrictions (eg costs, parking disc card, parking zone, etc). Currently supported in BE, FR, NL, IT, DE, LU, ES, PT, PL, CZ, AT

Topics

Resources

License

Stars

Watchers

Forks

Languages