domingo, 26 de junio de 2016

Estación metereológica gráfica en OpenHab




En este artículo explicaremos cómo incorporar la presentación de las lecturas de temperatura , humedad y presión atmosférica exterior de manera gráfica, dándole a nuestra página de OpenHab un aspecto mucho más llamativo del que tiene por defecto.

Para ello utilizaremos el servicio Weather de Yahoo, y una pequeña página web que insertamos en nuestra configuración de OpenHab.

Esto mismo lo podríamos realizar con otros proveedores como son:

pero hemos escogido Yahoo, por ser el único que no nos solicita registrarnos para obtener una “apikey”, en cambio nos solicitará un código “woeid”, el cual es más sencillo de obtener y explicaremos seguidamente como obtenerlo.

Obtención del código woeid

Una opción sencilla para obtener el código woeid, es acceder a la página web WOEID Lookup  http://woeid.rosselliot.co.nz/, una vez accedamos obtendremos la siguiente página:




En la casilla “Search Place”, deberemos de introducir nuestro código postal, seguidamente pulsar sobre “Lookup”, con ello en el campo “Results” aparecerán las coincidencias a nivel mundial del código introducido:



En la lista que nos presentarán deberemos de escoger la población correcta, ya  que como podréis observar, el mismo código postal se puede dar en diversos países. En mi caso,  selecciono Barcelona, Catalonia, Spain, donde el código a copiar es el 20078583.
Una vez copiado nuestro código woeid, pasaremos a configurar el weather en el fichero de configuración openhab.cfg.


Configuración de openhab.cfg

Desde el terminal (Putty en Windows o SSH en Linux), editaremos el fichero de configuración de OpenHab:

cd /opt/openhab/configurations

sudo nano openhab.cfg

Seguidamente buscaremos el apartado “Weather Binding”






Una vez localizado verificaremos si en la líneas centrales tenemos la instrucción “weather:location.home.woeid=”, si no es así la incorporaremos.

Descomentar las instrucciones:

#weather:location.<locationId1>.name=
#weather:location.<locationId1>.woeid=    
#weather:location.<locationId1>.provider=
#weather:location.<locationId1>.language=
#weather:location.<locationId1>.updateInterval=

Es decir, borrar el símbolo “#” de delante de cada línea. Seguidamente sustituiremos <locationId1> por home, y rellenaremos los datos después del símbolo igual “=”.

# location configuration, you can specify multiple locations
weather:location.home.name=Barcelona
weather:location.home.woeid=20078583    
weather:location.home.provider=yahoo
weather:location.home.language=es
weather:location.home.updateInterval=10

donde:
name es opcional pero cabe decir que será el nombre que figure en nuestro gráfico.
woeid es es código de localización geográfica, explicado en el capítulo anterior.
provider en el nombre del proveedor de servicios weather
language es el idioma
updateInterval es el intervalo en minutos para el refresco de datos

Salvar y salir con Ctrl + O, Enter, Ctrl X.



Configuración del fichero items

A continuación deberemos de crear el fichero weather.items en el directorio /opt/openhab/configurations/items .

Desde el terminal accederemos al directorio items:

cd /opt/openhab/configurations/items

Crearemos y editaremos el fichero weather.items
sudo nano weather.items
Una vez abierto el editor nano, incorporaremos las siguientes líneas:

Number   Temperature   "Temperature [%.2f °C]"   {weather="locationId=home, type=temperature, property=current"}

Number   Humidity      "Humidity [%d %%]"        {weather="locationId=home, type=atmosphere, property=humidity"}

Number   Pressure         "Pressure [%.2f mb]"    {weather="locationId=home, type=atmosphere, property=pressure"}


Salvar y salir con Ctrl + O, Enter, Ctrl X.


Configuración del fichero HTML

Deberemos de bajarnos el fichero comprimido con todos los archivos necesarios para su funcionamiento, de este enlace:

Copiar el fichero descargado en el directorio /tmp de la raspberry, mediante FileZilla o WinSCP.

Mover el fichero comprimido al directorio  /opt/openhab/webapps:

Ir al directorio /tmp
cd /tmp

Copiar el fichero a la carpeta webapps
sudo cp weather-data-1.8.zip /opt/openhab/webapps

Descomprimir el fichero:
sudo unzip weather-data-1.8.zip

Borrar el fichero comprimido
sudo rm weather-data-1.8.zip

Configuración del fichero sitemap

Cambiar a la carpeta sitemaps:
cd /opt/openhab/configurations/sitemaps
Editar el fichero sitemaps:
sudo nano souliss.sitemap
Y añadiremos las líneas mostradas en negrilla:

sitemap default label="Menú Principal"
{
Frame label="Souliss - Hello World" {
       Switch item=SimpleLight mappings=[ON="ON", OFF="OFF"]
Frame label="Graficos" {
Webview url="/weather?locationId=home&layout=example&iconset=colorful" height=7
   
    Text item=HEALTHNodo0 icon="icon16x16"
       Text item=TIMESTAMP_Nodo0 icon="icon16x16"
        }
    }      
}
Salvar y salir con Ctrl + O, Enter, Ctrl X.

Reiniciar OpenHab para que lea los cambios, y una vez cargado del todo ya podéis abrir la url para verificar el nuevo widget.



Otras opciones de personalización

Traducir algún literal



Evidentemente que podremos personalizar este widget, por ejemplo podremos traducir algunos literales como Humedad o Presión, para ello deberéis de editar el fichero example.html y sustituir los originales por los traducidos (ejemplo en negrilla):

<!DOCTYPE html>
<html>
<head>
   <meta http-equiv="Content-type" CONTENT="text/html; charset=utf-8">
   <link rel="stylesheet" type="text/css" href="weather-data/layouts/example.css" />
   <script type="text/javascript" src="weather-data/layouts/example.js"></script>
</head>

<body id="weather-body" onload="formatIframe()">
<left>
   <div id="weather-location-name">${config:name}, ${weather:condition.observationTime(%1$td.%1$tm.%1$tY %1$tH:%1$tM)}</div>

   <table id="weather-table">
      <tr>
          <td rowspan="2"><img id="weather-icon" src="weather-data/images/${param:iconset}/${weather:condition.commonId}.png"/></td>
          <td id="weather-temp">${weather:temperature.current(%.1f)}</td>
          <td id="weather-temp-sign">&#176;C</td>
      </tr>
      <tr>
          <td colspan="2">
              <table id="weather-table-details">
                  <tr>
                      <td>Humedad:</td>
                      <td>${weather:atmosphere.humidity} %</td>
                  </tr>
                  <tr>
                      <td>Presi&#243;n:</td>
                      <td>${weather:atmosphere.pressure(%.1f)} mb</td>
                  </tr>
              </table>
          </td>
      </tr>
   </table>

   <table id="weather-forecast-table">
      <tr>
          <td>Today</td>
          <td>${forecast(1):condition.observationTime(%1$tA)}</td>
          <td>${forecast(2):condition.observationTime(%1$tA)}</td>
      </tr>
      <tr>
          <td><img src="weather-data/images/${param:iconset}/${forecast(0):condition.commonId}.png"/></td>
          <td><img src="weather-data/images/${param:iconset}/${forecast(1):condition.commonId}.png"/></td>
          <td><img src="weather-data/images/${param:iconset}/${forecast(2):condition.commonId}.png"/></td>
      </tr>
      <tr>
          <td class="temp-max">${forecast(0):temperature.max(%.0f)}</td>
          <td class="temp-max">${forecast(1):temperature.max(%.0f)}</td>
          <td class="temp-max">${forecast(2):temperature.max(%.0f)}</td>
      </tr>
      <tr>
          <td class="temp-min">${forecast(0):temperature.min(%.0f)}</td>
          <td class="temp-min">${forecast(1):temperature.min(%.0f)}</td>
          <td class="temp-min">${forecast(2):temperature.min(%.0f)}</td>
      </tr>
   </table>
</left>
</body>

</html>

En este caso no se veía el acento de Presión y lo sustituí por su equivalente en asci &#243;.

Añadir más campos

El fichero weather.items, puede incluir más campos para añadir a nuestra estación metereológica, si estos son añadidos, posteriormente podremos invocarlos desde la página HTML.

Detalle de los items soportados:

// atmosphere
Number   Humidity         "Humidity [%d %%]"      {weather="locationId=home, type=atmosphere, property=humidity"}
Number   Visibility       "Visibility [%.2f km]"  {weather="locationId=home, type=atmosphere, property=visibility"}
Number   Visibility_Mph   "Visibility [%.2f mi]"  {weather="locationId=home, type=atmosphere, property=visibility, unit=mph"}
Number   Pressure         "Pressure [%.2f mb]"    {weather="locationId=home, type=atmosphere, property=pressure"}
Number   Pressure_Inches  "Pressure [%.2f in]"    {weather="locationId=home, type=atmosphere, property=pressure, unit=inches"}
String   Pressure_Trend   "Pressuretrend [%s]"    {weather="locationId=home, type=atmosphere, property=pressureTrend"}
Number   Ozone            "Ozone [%d ppm]"        {weather="locationId=home, type=atmosphere, property=ozone"}
Number   UV_Index         "UV Index"              {weather="locationId=home, type=atmosphere, property=uvIndex, scale=0"}

// clouds
Number   Clouds   "Clouds [%.0f %%]"   {weather="locationId=home, type=clouds, property=percent"}

// condition
String   Condition        "Condition [%s]"      {weather="locationId=home, type=condition, property=text"}
String   Condition_ID     "Condition id [%s]"   {weather="locationId=home, type=condition, property=id"}
DateTime ObservationTime  "Observation time [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"   {weather="locationId=home, type=condition, property=observationTime"}
DateTime LastUpdate       "Last update [%1$td.%1$tm.%1$tY %1$tH:%1$tM]"        {weather="locationId=home, type=condition, property=lastUpdate"}
String   CommonId         "Common id [%s]"      {weather="locationId=home, type=condition, property=commonId"}

// precipitation
Number   Rain          "Rain [%.2f mm/h]"   {weather="locationId=home, type=precipitation, property=rain"}
Number   Rain_Inches   "Rain [%.2f in/h]"   {weather="locationId=home, type=precipitation, property=rain, unit=inches"}
Number   Snow          "Snow [%.2f mm/h]"   {weather="locationId=home, type=precipitation, property=snow"}
Number   Snow_Inches   "Snow [%.2f in/h]"   {weather="locationId=home, type=precipitation, property=snow, unit=inches"}
Number   Precip_Probability   "Precip probability [%d %%]"   {weather="locationId=home, type=precipitation, property=probability"}
// new total property in 1.8, only Wunderground
Number   Precip_Total         "Precip total [%d mm]"   {weather="locationId=home, type=precipitation, property=total"}
Number   Precip_Total_Inches  "Precip total [%d in]"   {weather="locationId=home, type=precipitation, property=total, unit=inches"}

// temperature
Number   Temperature      "Temperature [%.2f °C]"       {weather="locationId=home, type=temperature, property=current"}
Number   Temperature_F    "Temperature [%.2f °F]"       {weather="locationId=home, type=temperature, property=current, unit=fahrenheit"}
Number   Temp_Feel        "Temperature feel [%.2f °C]"  {weather="locationId=home, type=temperature, property=feel"}
Number   Temp_Feel_F      "Temperature feel [%.2f °F]"  {weather="locationId=home, type=temperature, property=feel, unit=fahrenheit"}
Number   Temp_Dewpoint    "Dewpoint [%.2f °C]"          {weather="locationId=home, type=temperature, property=dewpoint"}
Number   Temp_Dewpoint_F  "Dewpoint [%.2f °F]"          {weather="locationId=home, type=temperature,
property=dewpoint, unit=fahrenheit"}
// min and max values only available in forecasts
Number   Temp_Min         "Temperature min [%.2f °C]"   {weather="locationId=home, type=temperature, property=min"}
Number   Temp_Min_F       "Temperature min [%.2f °F]"   {weather="locationId=home, type=temperature, property=min, unit=fahrenheit"}
Number   Temp_Max         "Temperature max [%.2f °C]"   {weather="locationId=home, type=temperature, property=max"}
Number   Temp_Max_F       "Temperature max [%.2f °F]"   {weather="locationId=home, type=temperature, property=max, unit=fahrenheit"}
String   Temp_MinMax      "Min/Max [%s °C]"             {weather="locationId=home, type=temperature, property=minMax"}
String   Temp_MinMax_F    "Min/Max [%s °F]"             {weather="locationId=home, type=temperature, property=minMax, unit=fahrenheit"}

// wind
Number   Wind_Speed           "Windspeed [%.2f km/h]"    {weather="locationId=home, type=wind, property=speed"}
Number   Wind_Speed_Beaufort  "Windspeed Beaufort [%d]"  {weather="locationId=home, type=wind, property=speed, unit=beaufort"}
Number   Wind_Speed_Knots     "Windspeed [%.2f kn]"      {weather="locationId=home, type=wind, property=speed, unit=knots"}
Number   Wind_Speed_Mps       "Windspeed [%.2f mps]"     {weather="locationId=home, type=wind, property=speed, unit=mps"}
Number   Wind_Speed_Mph       "Windspeed [%.2f mph]"     {weather="locationId=home, type=wind, property=speed, unit=mph"}
String   Wind_Direction       "Wind direction [%s]"      {weather="locationId=home, type=wind, property=direction"}
Number   Wind_Degree          "Wind degree [%.0f °]"     {weather="locationId=home, type=wind, property=degree"}
Number   Wind_Gust            "Wind gust [%.2f km/h]"    {weather="locationId=home, type=wind, property=gust"}
Number   Wind_Gust_Beaufort   "Wind gust Beaufort [%d]"  {weather="locationId=home, type=wind, property=gust, unit=beaufort"}
Number   Wind_Gust_Knots      "Wind gust [%.2f kn]"      {weather="locationId=home, type=wind, property=gust, unit=knots"}
Number   Wind_Gust_Mps        "Wind gust [%.2f mps]"     {weather="locationId=home, type=wind, property=gust, unit=mps"}
Number   Wind_Gust_Mph        "Wind gust [%.2f mph]"     {weather="locationId=home, type=wind, property=gust, unit=mph"}
Number   Wind_Chill           "Wind chill [%.2f °C]"     {weather="locationId=home, type=wind, property=chill"}
Number   Wind_Chill_F         "Wind chill [%.2f °F]"     {weather="locationId=home, type=wind, property=chill, unit=fahrenheit"}

// weather station (only Wunderground and Hamweather), needs version 1.7 or greater of the binding
String   Station_Name         "Station Name [%s]"        {weather="locationId=home, type=station, property=name"}
String   Station_Id           "Station Id [%s]"          {weather="locationId=home, type=station, property=id"}
Number   Station_Latitude     "Station Latitude [%.6f]"  {weather="locationId=home, type=station, property=latitude, scale=6"}
Number   Station_Longitude    "Station Longitude [%.6f]" {weather="locationId=home, type=station, property=longitude, scale=6"}

En fichero example.html de la carpeta webapps podríamos añadir nuevos campos, como en el ejemplo siguiente:

<td colspan="2">
              <table id="weather-table-details">
                  <tr>
                      <td>Humedad:</td>
                      <td>${weather:atmosphere.humidity} %</td>
                  </tr>
                  <tr>
                      <td>Presi&#243;n:</td>
                      <td>${weather:atmosphere.pressure(%.1f)} mb</td>
                  </tr>
                  <tr>
                      <td>Visivilidad:</td>
                      <td>${weather:atmosphere.visibility(%.1f)} km</td>
                  </tr>

Con lo que obtendremos la información de la visibilidad:

Y esto no es todo, con cuatro líneas de código HTML podemos ir añadiendo widgets como en la siguiente imágen, pero eso será otra historia...









7 comentarios:

  1. Interesante aportacion =) Lo pondre en mi OH.
    Yo tambien utilizo el binding Astro para saber la hora de la puesta y salida del sol y otros datos.

    Salu2

    ResponderEliminar
  2. Buenas he seguido los pasos como as indicado y no me carga el widget. Me muestra el recuadro donde mostrará el widget pero me da un error que es el siguiente:

    HTTP ERROR 404
    Problem accessing /weather. Reason:
    ProxyServlet: /weather

    A ver si me puedes ayudar.

    ResponderEliminar
    Respuestas
    1. Buenas tardes Juan José, en principio este error es debido a que todavía no se ha iniciado todo el proceso de arranque en OpenHab, dale un tiempo (largo) y vuelve a probar.

      Eliminar
    2. A mi me pasa lo mismo y lo he reiniciado varias veces ¿sabemos porque puede ser?

      Eliminar
  3. Hola Pep. Me pasa lo mismo que a Juan Jose sobre el error y despues de un largo tiempo me aparece lo siguiente:
    HTTP ERROR 500

    Problem accessing /weather. Reason:

    File with weather layout 'example.html' does not exist, make sure it is in the layouts folder ./webapps/weather-data/layouts
    Caused by:

    javax.servlet.ServletException: File with weather layout 'example.html' does not exist, make sure it is in the layouts folder ./webapps/weather-data/layouts
    at org.openhab.binding.weather.internal.gfx.WeatherServlet.doGet(WeatherServlet.java:113)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:735)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.equinox.http.servlet.internal.ServletRegistration.service(ServletRegistration.java:61)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.processAlias(ProxyServlet.java:128)
    at org.eclipse.equinox.http.servlet.internal.ProxyServlet.service(ProxyServlet.java:60)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:598)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:486)
    at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1065)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:413)
    at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:192)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:999)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
    at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:250)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:149)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:111)
    at org.eclipse.jetty.server.Server.handle(Server.java:350)
    at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:454)
    at org.eclipse.jetty.server.AbstractHttpConnection.headerComplete(AbstractHttpConnection.java:890)
    at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.headerComplete(AbstractHttpConnection.java:944)
    at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:630)
    at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:230)
    at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:77)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:606)
    at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:46)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:603)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:538)
    at java.lang.Thread.run(Thread.java:745)

    Tienes idea a que se puede deber? Gracias

    ResponderEliminar
    Respuestas
    1. Hola Javier, por lo que se ve no se encuentra el fichero example.html, supongo que ya habrás verificado las rutas y el nombre del fichero (mayúsculas y minúsculas). Si es así mira de reinstalar el Java. Estoy de vacaciones y no puedo hacer pruebas, por otra parte comentar que la lectura se realiza cada 10 minutos para no bloquear el servicio, lo podéis modificar en el cfg, pero una vez verificado volver a poner los 10 min, para evitar que os bloqueen.

      Eliminar
    2. Hola Javier, por lo que se ve no se encuentra el fichero example.html, supongo que ya habrás verificado las rutas y el nombre del fichero (mayúsculas y minúsculas). Si es así mira de reinstalar el Java. Estoy de vacaciones y no puedo hacer pruebas, por otra parte comentar que la lectura se realiza cada 10 minutos para no bloquear el servicio, lo podéis modificar en el cfg, pero una vez verificado volver a poner los 10 min, para evitar que os bloqueen.

      Eliminar