diff --git a/modules/mareeinfo/__init__.py b/modules/mareeinfo/__init__.py
new file mode 100644
index 00000000..0588edee
--- /dev/null
+++ b/modules/mareeinfo/__init__.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 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 MareeinfoBackend
+
+
+__all__ = ['MareeinfoBackend']
diff --git a/modules/mareeinfo/backend.py b/modules/mareeinfo/backend.py
new file mode 100644
index 00000000..02e1de88
--- /dev/null
+++ b/modules/mareeinfo/backend.py
@@ -0,0 +1,68 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 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.base import find_object
+from weboob.capabilities.gauge import CapGauge, Gauge, SensorNotFound
+from .browser import MareeinfoBrowser
+
+
+__all__ = ['MareeinfoBackend']
+
+
+class MareeinfoBackend(BaseBackend, CapGauge):
+ NAME = 'mareeinfo'
+ DESCRIPTION = u'Un module qui permet d\' aller a la pĂȘche aux moules totalement informĂ©'
+ MAINTAINER = u'Bezleputh'
+ EMAIL = 'carton_ben@yahoo.fr'
+ LICENSE = 'AGPLv3+'
+ VERSION = '1.0'
+
+ BROWSER = MareeinfoBrowser
+
+ def get_last_measure(self, sensor_id):
+ gauge_id = sensor_id.split('-')[0]
+ return find_object(self.iter_sensors(gauge_id), id=sensor_id, error=SensorNotFound).lastvalue
+
+ def iter_gauge_history(self, sensor_id):
+ gauge_id = sensor_id.split('-')[0]
+ return find_object(self.iter_sensors(gauge_id), id=sensor_id, error=SensorNotFound).history
+
+ def iter_gauges(self, pattern=None):
+ for _gauge in self.browser.get_harbor_list(pattern):
+ if pattern is not None:
+ gauge = self.browser.get_harbor_infos(_gauge)
+ yield gauge
+ else:
+ yield _gauge
+
+ def iter_sensors(self, gauge, pattern=None):
+ if not isinstance(gauge, Gauge):
+ gauge = find_object(self.iter_gauges(), id=gauge, error=SensorNotFound)
+
+ gauge = self.browser.get_harbor_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
diff --git a/modules/mareeinfo/browser.py b/modules/mareeinfo/browser.py
new file mode 100644
index 00000000..e476bbab
--- /dev/null
+++ b/modules/mareeinfo/browser.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 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.browser2 import PagesBrowser, URL
+
+from .pages import IndexPage
+
+
+class MareeinfoBrowser(PagesBrowser):
+ BASEURL = 'http://maree.info'
+
+ harbor_page = URL('', '(?P<_id>.*)', IndexPage)
+
+ def get_harbor_list(self, pattern):
+ return self.harbor_page.go().get_harbor_list(pattern=pattern)
+
+ def get_harbor_infos(self, gauge):
+ return self.harbor_page.go(_id=gauge.id).get_harbor_infos(obj=gauge)
diff --git a/modules/mareeinfo/pages.py b/modules/mareeinfo/pages.py
new file mode 100644
index 00000000..a70f494f
--- /dev/null
+++ b/modules/mareeinfo/pages.py
@@ -0,0 +1,205 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 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.browser2.page import HTMLPage, method
+from weboob.tools.browser2.elements import ListElement, ItemElement
+from weboob.tools.browser2.filters import CleanText, Link, DateTime, CleanDecimal, Regexp, XPath
+from weboob.capabilities.gauge import Gauge, GaugeMeasure, GaugeSensor
+from datetime import timedelta
+import re
+
+
+class IndexPage(HTMLPage):
+ @method
+ class get_harbor_list(ListElement):
+ item_xpath = "//a[@class='Port PP'] | //a[@class='Port PS']"
+
+ class item(ItemElement):
+ klass = Gauge
+
+ obj_id = CleanText(Link('.'), replace=[('/', '')])
+ obj_name = CleanText('.')
+ obj_city = CleanText('.')
+ obj_object = u'Port'
+
+ def validate(self, obj):
+ if self.env['pattern']:
+ return self.env['pattern'].lower() in obj.name.lower()
+ return True
+
+ @method
+ class get_harbor_infos(ItemElement):
+ klass = Gauge
+
+ def _create_coef_sensor(self, gauge_id, AM=True):
+ name = CleanText('//tr[@class="MJE"]/th[4]')(self)
+ _name = 'matin' if AM else 'aprem'
+ value = self._get_coef_value(AM=AM)
+
+ if value:
+ coef = GaugeSensor(u'%s-%s-%s' % (gauge_id, name, _name))
+ coef.name = '%s %s' % (name, _name)
+ coef.lastvalue = value
+ coef.gaugeid = gauge_id
+
+ coef.history = []
+ for jour in range(0, 7):
+ measure = self._get_coef_value(AM=AM, jour=jour)
+ if measure:
+ coef.history.append(measure)
+
+ return coef
+
+ def _get_coef_value(self, AM=True, jour=0):
+ if AM:
+ time = DateTime(CleanText('//tr[@id="MareeJours_%s"]/td[1]/b[1]' % jour))(self)
+ value = CleanText('//tr[@id="MareeJours_%s"]/td[3]/b[1]' % jour)(self)
+ else:
+ time, value = None, None
+ if len(XPath('//tr[@id="MareeJours_%s"]/td[1]/b' % jour)(self)) > 1:
+ time = DateTime(CleanText('//tr[@id="MareeJours_%s"]/td[1]/b[2]' % jour))(self)
+ value = CleanText('//tr[@id="MareeJours_%s"]/td[3]/b[2]' % jour)(self)
+
+ if time and value:
+ measure = GaugeMeasure()
+ measure.level = float(value)
+ measure.date = time + timedelta(days=jour)
+ return measure
+
+ def _create_high_tide(self, gauge_id, AM=True):
+ name = CleanText('//tr[@class="MJE"]/th[3]')(self)
+ _name = 'matin' if AM else 'aprem'
+ value = self._get_high_tide_value(AM=AM)
+
+ if value:
+ tide = GaugeSensor(u'%s-%s-%s' % (gauge_id, name, _name))
+ tide.name = u'Pleine Mer %s' % (_name)
+ tide.unit = u'm'
+ tide.lastvalue = value
+ tide.gaugeid = gauge_id
+
+ tide.history = []
+ for jour in range(0, 7):
+ measure = self._get_high_tide_value(AM=AM, jour=jour)
+ if measure:
+ tide.history.append(measure)
+
+ return tide
+
+ def _get_high_tide_value(self, AM=True, jour=0):
+ if AM:
+ time = DateTime(CleanText('//tr[@id="MareeJours_%s"]/td[1]/b[1]' % jour))(self)
+ value = CleanDecimal('//tr[@id="MareeJours_0"]/td[2]/b[1]', replace_dots=True)(self)
+ else:
+ time, value = None, None
+ if len(XPath('//tr[@id="MareeJours_%s"]/td[1]/b' % jour)(self)) > 1:
+ time = DateTime(CleanText('//tr[@id="MareeJours_%s"]/td[1]/b[2]' % jour),
+ default=None)(self)
+ value = CleanDecimal('//tr[@id="MareeJours_0"]/td[2]/b[2]', replace_dots=True,
+ default=None)(self)
+
+ if time and value:
+ measure = GaugeMeasure()
+ measure.level = float(value)
+ measure.date = time + timedelta(days=jour)
+ return measure
+
+ def _create_low_tide(self, gauge_id, AM=True):
+ name = CleanText('//tr[@class="MJE"]/th[3]')(self)
+ _name = 'matin' if AM else 'aprem'
+ value = self._get_low_tide_value(AM=AM)
+
+ if value:
+ tide = GaugeSensor(u'%s-%s-%s' % (gauge_id, name, _name))
+ tide.name = u'Basse Mer %s' % (_name)
+ tide.unit = u'm'
+ tide.lastvalue = value
+ tide.gaugeid = gauge_id
+
+ tide.history = []
+ for jour in range(0, 7):
+ measure = self._get_low_tide_value(AM=AM, jour=jour)
+ if measure:
+ tide.history.append(measure)
+
+ return tide
+
+ def _is_low_tide_first(self, jour):
+ return XPath('//tr[@id="MareeJours_%s"]/td[1]' % jour)(self)[0].getchildren()[0].tag != 'b'
+
+ def _get_low_tide_value(self, AM=True, jour=0):
+ slow_tide_pos = 1 if self._is_low_tide_first(jour) else 2
+ m = re.findall('(\d{2}h\d{2})', CleanText('//tr[@id="MareeJours_%s"]/td[1]' % jour)(self))
+
+ re_time = '(\d{2}h\d{2}).*(\d{2}h\d{2}).*(\d{2}h\d{2})'
+ re_value = '(.*)m(.*)m(.*)m'
+ if len(m) > 3:
+ re_time = '(\d{2}h\d{2}).*(\d{2}h\d{2}).*(\d{2}h\d{2}).*(\d{2}h\d{2})'
+ re_value = '(.*)m(.*)m(.*)m(.*)m'
+
+ if AM:
+ time = DateTime(Regexp(CleanText('//tr[@id="MareeJours_%s"]/td[1]' % jour),
+ re_time,
+ '\\%s' % slow_tide_pos))(self)
+
+ value = CleanDecimal(Regexp(CleanText('//tr[@id="MareeJours_%s"]/td[2]' % jour),
+ re_value,
+ '\\%s' % slow_tide_pos),
+ replace_dots=True, default=None)(self)
+
+ else:
+ slow_tide_pos += 2
+ time, value = None, None
+ if len(m) > slow_tide_pos - 1:
+ time = DateTime(Regexp(CleanText('//tr[@id="MareeJours_%s"]/td[1]' % jour),
+ re_time,
+ '\\%s' % slow_tide_pos))(self)
+
+ value = CleanDecimal(Regexp(CleanText('//tr[@id="MareeJours_%s"]/td[2]' % jour),
+ re_value,
+ '\\%s' % slow_tide_pos),
+ replace_dots=True, default=None)(self)
+
+ if time and value:
+ measure = GaugeMeasure()
+ measure.level = float(value)
+ measure.date = time + timedelta(days=jour)
+ return measure
+
+ def obj_sensors(self):
+ sensors = []
+ high_tide_PM = self._create_high_tide(self.obj.id)
+ if high_tide_PM:
+ sensors.append(high_tide_PM)
+ high_tide_AM = self._create_high_tide(self.obj.id, AM=False)
+ if high_tide_AM:
+ sensors.append(high_tide_AM)
+ low_tide_AM = self._create_low_tide(self.obj.id)
+ if low_tide_AM:
+ sensors.append(low_tide_AM)
+ low_tide_PM = self._create_low_tide(self.obj.id, AM=False)
+ if low_tide_PM:
+ sensors.append(low_tide_PM)
+ coef_AM = self._create_coef_sensor(self.obj.id)
+ if coef_AM:
+ sensors.append(coef_AM)
+ coef_PM = self._create_coef_sensor(self.obj.id, AM=False)
+ if coef_PM:
+ sensors.append(coef_PM)
+ return sensors
diff --git a/modules/mareeinfo/test.py b/modules/mareeinfo/test.py
new file mode 100644
index 00000000..8e6f1942
--- /dev/null
+++ b/modules/mareeinfo/test.py
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+# Copyright(C) 2014 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 MareeinfoTest(BackendTest):
+ BACKEND = 'mareeinfo'
+
+ def test_mareeinfo(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)
+ self.assertTrue(len(self.backend.iter_gauge_history(sensor.id)) > 0)