diff --git a/modules/vlille/__init__.py b/modules/vlille/__init__.py
new file mode 100644
index 00000000..95e4ca19
--- /dev/null
+++ b/modules/vlille/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013 Bezleputh
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+
+from .backend import VlilleBackend
+
+
+__all__ = ['VlilleBackend']
diff --git a/modules/vlille/backend.py b/modules/vlille/backend.py
new file mode 100644
index 00000000..139d2195
--- /dev/null
+++ b/modules/vlille/backend.py
@@ -0,0 +1,81 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013 Bezleputh
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+
+from weboob.tools.backend import BaseBackend
+from weboob.capabilities.gauge import ICapGauge,GaugeSensor, Gauge, SensorNotFound
+
+from .browser import VlilleBrowser
+
+__all__ = ['VlilleBackend']
+
+class VlilleBackend(BaseBackend, ICapGauge):
+ NAME = 'vlille'
+ DESCRIPTION = u'accès aux données vlille'
+ MAINTAINER = u'Bezleputh'
+ EMAIL = 'carton_ben@yahoo.fr'
+ VERSION = '0.f'
+
+ BROWSER = VlilleBrowser
+
+ def iter_gauges(self, pattern=None):
+ if pattern is None:
+ for gauge in self.browser.get_station_list():
+ yield gauge
+ else:
+ lowpattern = pattern.lower()
+ for gauge in self.browser.get_station_list():
+ if lowpattern in gauge.name.lower():
+ yield gauge
+
+ def iter_sensors(self, gauge, pattern=None):
+ if not isinstance(gauge, Gauge):
+ gauge = self._get_gauge_by_id(gauge)
+ if gauge is None:
+ raise SensorNotFound()
+
+ gauge.sensors = self.browser.get_station_infos(gauge)
+ if pattern is None:
+ for sensor in gauge.sensors:
+ yield sensor
+ else:
+ lowpattern = pattern.lower()
+ for sensor in gauge.sensors:
+ if lowpattern in sensor.name.lower():
+ yield sensor
+
+ def get_last_measure(self, sensor):
+ if not isinstance(sensor, GaugeSensor):
+ sensor = self._get_sensor_by_id(sensor)
+ if sensor is None:
+ raise SensorNotFound()
+ return sensor.lastvalue
+
+ def _get_gauge_by_id(self, id):
+ for gauge in self.browser.get_station_list():
+ if id == gauge.id:
+ return gauge
+ return None
+
+ def _get_sensor_by_id(self, id):
+ for gauge in self.browser.get_station_list():
+ for sensor in self.browser.get_station_infos(gauge):
+ if id == sensor.id:
+ return sensor
+ return None
diff --git a/modules/vlille/browser.py b/modules/vlille/browser.py
new file mode 100644
index 00000000..d7fe69ee
--- /dev/null
+++ b/modules/vlille/browser.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013 Bezleputh
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+
+from weboob.tools.browser import BaseBrowser
+
+from .pages import ListStationsPage, InfoStationPage
+
+
+__all__ = ['VlilleBrowser']
+
+
+class VlilleBrowser(BaseBrowser):
+ PROTOCOL = 'http'
+ DOMAIN = 'www.vlille.fr/stations'
+ ENCODING = None
+
+ PAGES = {
+ '%s://%s/xml-station.aspx\?borne=.*' % (PROTOCOL, DOMAIN): InfoStationPage,
+ '%s://%s/xml-stations.aspx' % (PROTOCOL, DOMAIN): ListStationsPage,
+ }
+
+ def get_station_list(self):
+ if not self.is_on_page(ListStationsPage):
+ self.location(u'%s://%s/xml-stations.aspx' % (self.PROTOCOL, self.DOMAIN))
+ return self.page.get_station_list()
+
+ def get_station_infos(self, gauge):
+ self.location('%s://%s/xml-station.aspx?borne=%s' % (self.PROTOCOL, self.DOMAIN, gauge.id))
+ return self.page.get_station_infos(gauge.id)
diff --git a/modules/vlille/pages.py b/modules/vlille/pages.py
new file mode 100644
index 00000000..08a7b18c
--- /dev/null
+++ b/modules/vlille/pages.py
@@ -0,0 +1,103 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013 Bezleputh
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+
+from weboob.tools.browser import BasePage
+from weboob.capabilities.gauge import Gauge, GaugeMeasure, GaugeSensor
+from weboob.capabilities.base import NotAvailable, NotLoaded
+import datetime, re
+
+__all__ = ['InfoStationPage', 'ListStationsPage']
+
+
+class InfoStationPage(BasePage):
+ def _create_bikes_sensor(self, value, gauge_id, last_update, adresse):
+ levelbikes = GaugeSensor(gauge_id + '-bikes')
+ levelbikes.name = u'Bikes'
+ levelbikes.forecast = u'%s' %adresse
+ lastvalue = GaugeMeasure()
+ lastvalue.level = float(value)
+ lastvalue.date = last_update
+ lastvalue.alarm = u'0'
+ levelbikes.lastvalue = lastvalue
+ levelbikes.history = NotLoaded
+ levelbikes.gaugeid = gauge_id
+ return levelbikes
+
+ def _create_attach_sensor(self, value, gauge_id, last_update, adresse):
+ levelattach = GaugeSensor(gauge_id + '-attach')
+ levelattach.name = u'Attach'
+ levelattach.forecast = u'%s' %adresse
+ lastvalue = GaugeMeasure()
+ lastvalue.level = float(value)
+ lastvalue.date = last_update
+ lastvalue.alarm = u'0'
+ levelattach.lastvalue = lastvalue
+ levelattach.history = NotLoaded
+ levelattach.gaugeid = gauge_id
+ return levelattach
+
+ def _create_status_sensor(self, value, gauge_id, last_update, adresse):
+ levelstatus = GaugeSensor(gauge_id + '-status')
+ levelstatus.name = u'Status'
+ levelstatus.forecast = u'%s' %adresse
+ lastvalue = GaugeMeasure()
+ status = float(value)
+ if status == 0:
+ status = 1
+ else:
+ status = -1
+ lastvalue.level = float(status)
+ lastvalue.date = last_update
+ lastvalue.alarm = u'-1'
+ levelstatus.lastvalue = lastvalue
+ levelstatus.history = NotLoaded
+ levelstatus.gaugeid = gauge_id
+ return levelstatus
+
+ def _get_last_update(self, last_update):
+ return datetime.datetime.now() - datetime.timedelta(seconds=int(re.match(r'\d+', last_update).group(0)))
+
+ def get_station_infos(self, gauge_id):
+
+ last_update = self._get_last_update(self.parser.select(self.document.getroot(),'lastupd',1).text)
+ sensors = []
+
+ adresse = self.parser.select(self.document.getroot(),'adress',1).text
+
+ sensors.append(self._create_bikes_sensor(self.parser.select(self.document.getroot(),'bikes',1).text, gauge_id, last_update, adresse))
+
+ sensors.append(self._create_attach_sensor(self.parser.select(self.document.getroot(),'attachs',1).text, gauge_id, last_update, adresse))
+
+ sensors.append(self._create_status_sensor(self.parser.select(self.document.getroot(),'status',1).text, gauge_id, last_update, adresse))
+
+ #print self.parser.select(self.document.getroot(),'paiement',1).text
+
+ return sensors
+
+class ListStationsPage(BasePage):
+ def get_station_list(self):
+ gauges = []
+ for marker in self.parser.select(self.document.getroot(), 'marker'):
+ gauge = Gauge(int(marker.get('id')))
+ gauge.name = unicode(marker.get('name'))
+ gauge.city = gauge.name
+ gauge.object = u'vLille'
+ gauges.append(gauge)
+ return gauges
diff --git a/modules/vlille/test.py b/modules/vlille/test.py
new file mode 100644
index 00000000..cd78ebde
--- /dev/null
+++ b/modules/vlille/test.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2013 Bezleputh
+#
+# This file is part of weboob.
+#
+# weboob is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# weboob is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with weboob. If not, see .
+
+from weboob.tools.test import BackendTest
+
+class VlilleTest(BackendTest):
+ BACKEND = 'vlille'
+
+ def test_vlille(self):
+ l = list(self.backend.iter_gauges())
+ self.assertTrue(len(l) > 0)
+
+ gauge = l[0]
+ s = list(self.backend.iter_sensors(gauge))
+ self.assertTrue(len(s) > 0)
+
+ sensor = s[0]
+ self.assertTrue(self.backend.get_last_measure(sensor.id) is not None)