RMV transport departures

Jep now I saw the rmv-card and reinstalled it but it don’t change the view an the log-entries:
grafik

I need to take a look next week.

1 Like

Edit:

Noob me, adding the card to the resources is done automatically.

Fresh HA (Docker) installation here, works fine for me.

  • Installed rmv-card via HACS
  • Edited in RAW Mode, throw this at top
resources:
  - url: /config/www/community/rmv-card/rmv-card.js?v=0
    type: js

and this under cars:

    cards:
      - type: 'custom:rmv-card'
        entity:
          - sensor.<<insertStationsensorName>>

Just to drop some idea, i think it would be nice to have the card more like a real Frankfurt Station Sign. If the train,bus, etc is more than 60 minutes away (i guess thats the default) it should show the real time, not the minutes.

But, works nice for me, so thanks! :slight_smile:

I am very satisfied with that card. But only one more thing should be nice, if in addition to the “arriving minutes” also the planned departure time would be displayed.

Had the same idea!

So i added a little bit quick & dirty code and there we have it:

grafik

As far as i remembered, i just deleted the .js.gz file and added those 3 variables and enhanced the <td> with the new variables. Some <small> as dirty styling format.

      const hours = (jtime.getUTCHours()<10?'0':'') + jtime.getUTCHours()
      const minutes = (jtime.getUTCMinutes()<10?'0':'') + jtime.getUTCMinutes()
      const depTime = `(${hours}:${minutes})`

      tablehtml += `
          <tr>
            <td class="shrink" style="text-align:center;"><span class="line ${product} ${linename}">${linename}</span></td>
            <td class="expand">${destination}</td>
            <td class="shrink" style="text-align:right;">${time} <small>${depTime}</small></td>
          </tr>
      `

Note: No javascript developer here. Take care.

@cgtobi

I also saw those strange behaviour around midnight. I guess this is based on the enforcement of the UTC timezone and pressing the dates from the RMV API into that.
As i totally understand working with dates in ‘plain’ javascript is a total pain, i am curios if you tried using something like moment.js or similiar?

3 Likes

@MaxW thanks so much!!
That means i also need to delete the gzip file and edit the rmv-card.js?
What is this rmv-card.js.gz for? Only a zipped copy of the script. Is it necessary to have it in the folder?

The gzip file contains an compressed version of the rmv-card.js. The main purpose is to speedup loading times as modern browsers will prefere the compressed version over the non compressed. For compatibiliy reasons the uncompressed file is also available.
(This is a very complex thing, as there are many implementations based on the webserver, the client, caching proxy and others.)

You could compress it back, but i don’t really care about that 3.1 KiloBytes. I guess we talk about less than 10 millisecons.

I did not deceide yet how i will continue with this modification. Maybe i clean it up and provide it as PullRequest for @cgtobi to have it as additonal feature. Are you intrested?
Else i can simply fork it and do my own version of it.

This manually overwriting will work fine until he releases a new version of his card. Then HASC will overwrite it.

So, long story short: Yes, delete the gzip file and edit the rmv-card.js.
Here is mine for reference in total. You could copy paste it, or adjust it manually and lern a little bit :wink:


class RmvCard extends HTMLElement {
  set hass (hass) {
    const entityId = this.config.entity
    const state = hass.states[entityId]
    const name = state.attributes['friendly_name']

    if (!this.content) {
      const card = document.createElement('ha-card')
      card.header = name
      this.content = document.createElement('div')
      const style = document.createElement('style')
      style.textContent = `
        table {
          width: 100%;
          padding: 6px 14px;
        }
        td {
          padding: 3px 0px;
        }
        td.shrink {
          white-space:nowrap;
        }
        td.expand {
          width: 99%
        }
        span.line {
          font-weight: bold;
          font-size:0.9em;
          padding:3px 8px 2px 8px;
          color: #fff;
          background-color: #888;
          margin-right:0.7em;
        }
        span.S {
          background-color: #009252;
        }
        span.U-Bahn {
          background-color: #0067ad;
        }
        span.Tram {
          background-color: #eb6810;
        }
        span.Bus {
          background-color: #a3047a;
        }
        span.Bahn {
          background-color: #000000;
        }
        `
      card.appendChild(style)
      card.appendChild(this.content)
      this.appendChild(card)
    }

    var tablehtml = `
    <table>
    `
    const now = new Date()
    const utc = Date.UTC(now.getFullYear(), now.getMonth(), now.getDate(),
      now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds())
    const next = {
      'line': state.attributes['line'],
      'product': state.attributes['product'],
      'destination': state.attributes['destination'],
      'departure_time': state.attributes['departure_time'],
      'direction': state.attributes['direction']
    }
    const journeys = [next].concat(state.attributes['next_departures'])
    for (const journey of journeys) {
      var destination = journey['destination']
      if (typeof journey['destination'] === 'undefined') {
        destination = journey['direction']
      }
      const linename = journey['line']
      const product = journey['product']

      const jtime = new Date(journey['departure_time'] + 'Z')
      const time = parseInt((jtime.getTime() - utc) / 60000)
      
      const hours = (jtime.getUTCHours()<10?'0':'') + jtime.getUTCHours()
      const minutes = (jtime.getUTCMinutes()<10?'0':'') + jtime.getUTCMinutes()
      const depTime = `(${hours}:${minutes})`

      tablehtml += `
          <tr>
            <td class="shrink" style="text-align:center;"><span class="line ${product} ${linename}">${linename}</span></td>
            <td class="expand">${destination}</td>
            <td class="shrink" style="text-align:right;">${time} <small>${depTime}</small></td>
          </tr>
      `
    }
    tablehtml += `
    </table>
    `

    this.content.innerHTML = tablehtml
  }

  setConfig (config) {
    if (!config.entity) {
      throw new Error('You need to define an entity')
    }
    this.config = config
  }

  getCardSize () {
    return 1
  }
}

customElements.define('rmv-card', RmvCard)


2 Likes

of course … very interested. thanks for that clear explanation. i will implement it at weekend, when i have enough time :slight_smile: seems to be quit easy. thanks so much!

managed to capture a screenshot of those strange minutes:

grafik

As 1441 equals roughly 24h and a little, which would lead to the correct time, but one day to late.

The more i look at this, i am confused why there is a calculation at all, as the sensor is already providing the minutes?
grafik

Indeed, this looks promising to me. I dropped the UTC calculation magic and simply used the minutes provided by the sensor attribute:

class RmvCard extends HTMLElement {
  set hass (hass) {
    const entityId = this.config.entity
    const state = hass.states[entityId]
    const name = state.attributes['friendly_name']

    if (!this.content) {
      const card = document.createElement('ha-card')
      card.header = name
      this.content = document.createElement('div')
      const style = document.createElement('style')
      style.textContent = `
        table {
          width: 100%;
          padding: 6px 14px;
        }
        td {
          padding: 3px 0px;
        }
        td.shrink {
          white-space:nowrap;
        }
        td.expand {
          width: 99%
        }
        span.line {
          font-weight: bold;
          font-size:0.9em;
          padding:3px 8px 2px 8px;
          color: #fff;
          background-color: #888;
          margin-right:0.7em;
        }
        span.S {
          background-color: #009252;
        }
        span.U-Bahn {
          background-color: #0067ad;
        }
        span.Tram {
          background-color: #eb6810;
        }
        span.Bus {
          background-color: #a3047a;
        }
        span.Bahn {
          background-color: #000000;
        }
        `
      card.appendChild(style)
      card.appendChild(this.content)
      this.appendChild(card)
    }

    var tablehtml = `
    <table>
    `
    const next = {
      'line': state.attributes['line'],
      'product': state.attributes['product'],
      'destination': state.attributes['destination'],
      'departure_time': state.attributes['departure_time'],
      'direction': state.attributes['direction'],
      'minutes': state.attributes['minutes']
    }
    const journeys = [next].concat(state.attributes['next_departures'])
    for (const journey of journeys) {
      var destination = journey['destination']
      if (typeof journey['destination'] === 'undefined') {
        destination = journey['direction']
      }
      const linename = journey['line']
      const product = journey['product']

      const jtime = new Date(journey['departure_time'] + 'Z')      
      const hours = (jtime.getUTCHours() <10 ? '0' : '') + jtime.getUTCHours()
      const minutes = (jtime.getUTCMinutes() < 10 ? '0': '') + jtime.getUTCMinutes()
      const depTime = `(${hours}:${minutes})`

      tablehtml += `
          <tr>
            <td class="shrink" style="text-align:center;"><span class="line ${product} ${linename}">${linename}</span></td>
            <td class="expand">${destination}</td>
            <td class="shrink" style="text-align:right;">${journey['minutes']} <small>${depTime}</small></td>
          </tr>
      `
    }
    tablehtml += `
    </table>
    `

    this.content.innerHTML = tablehtml
  }

  setConfig (config) {
    if (!config.entity) {
      throw new Error('You need to define an entity')
    }
    this.config = config
  }

  getCardSize () {
    return 1
  }
}

customElements.define('rmv-card', RmvCard)

grafik

Please check out the latest version on GitHub - custom-cards/rmv-card: Custom card for the RMV component. or straight from HACS.

I’ve added a few options:

Title

friendly_name: My custom name
hide_title: true

Departure time and minutes

hide_minutes: true
show_time: true

1 Like

Thx, works nice for me!

You might want to drop superflous code around here: https://github.com/cgtobi/rmv-card/blob/4d2868944703af8dcbdd5c3825f98e85b65f5eab/rmv-card.js#L59

2 Likes

Well spotted. The new features are now available via HACS.

Hi @cgtobi! thx! it works now!
With the destination “Frankfurt (Main) Dornbusch” seems to be a bug. however!
I decided to use “Frankfurt (Main) Südbahnhof” instead. know it works fine :slight_smile:

sensor: 
.
.
.
  - platform: rmvtransport
    scan_interval: 120
    timeout: 10
    next_departure:
      - station: 3002398
        time_offset: 5
        max_journeys: 6
        name: BadHomburg
        destinations:
          - 'Bad Homburg v.d.H.-Ober-Eschbach (U)'
        products:
          - 'U-Bahn'
          - 'Bus'
  - platform: rmvtransport
    scan_interval: 120
    timeout: 10
    next_departure:
      - station: 3002398
        time_offset: 5
        max_journeys: 6
        name: Suedbahnhof
        destinations:
          - 'Frankfurt (Main) Südbahnhof'
        products:
          - 'U-Bahn'
          - 'Bus'

thx a lot!

1 Like

This is so nice! Thanks a lot. A question from my side: would it be possible to show “minutes” or something like “min” behind the number?

Hi,

My card is giving me an “Invalid Time Value” error.

The Card config is as simple as:

type: custom:rmv-card
entity:
  - sensor.karben_burg_grafenrode_friedhof

The sensor is setup as the following (in sensor.yaml):

- platform: rmvtransport
  next_departure:
    - station: 3022913
      time_offset: 5
      destinations:
        - "Karben-Groß-Karben Gesamtschule"
      products:
        - "Bus"

The entity has been created successful, however the state of the created sensor is unavailable

Any hints on how to get this solved?!

Best,
goeste

This is what I can see from the logs:

File "/usr/src/homeassistant/homeassistant/components/rmvtransport/sensor.py", line 190, in async_update
    await self.data.async_update()
  File "/usr/src/homeassistant/homeassistant/components/rmvtransport/sensor.py", line 237, in async_update
    _data = await self.rmv.get_departures(
  File "/usr/local/lib/python3.10/site-packages/RMVtransport/rmvtransport.py", line 78, in get_departures
    raise RMVtransportError(err) from err

followed by

2022-09-01 09:39:11.251 ERROR (MainThread) [homeassistant.helpers.entity] Update for sensor.rmv_journey fails
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/RMVtransport/rmvtransport.py", line 74, in get_departures
    for journey in self.obj.SBRes.JourneyList.Journey:
  File "src/lxml/objectify.pyx", line 234, in lxml.objectify.ObjectifiedElement.__getattr__
  File "src/lxml/objectify.pyx", line 453, in lxml.objectify._lookupChildOrRaise
AttributeError: no such child: JourneyList

and

File "/usr/src/homeassistant/homeassistant/components/rmvtransport/sensor.py", line 190, in async_update
    await self.data.async_update()
  File "/usr/src/homeassistant/homeassistant/components/rmvtransport/sensor.py", line 237, in async_update
    _data = await self.rmv.get_departures(
  File "/usr/local/lib/python3.10/site-packages/RMVtransport/rmvtransport.py", line 78, in get_departures
    raise RMVtransportError(err) from err
RMVtransport.errors.RMVtransportError: no such child: JourneyList

Probably, the connection to the API is broken?

Hello! I opened an issue on github, but I wanted to cover all bases :slight_smile:

The card doesn’t show up for me. I installed it via HACS and it just doesn’t show up. Logs aren’t mentioning the card at all.

€: Ok, figured it out. Was my own fault. Sorry!