|
1
|
|
|
""" |
|
2
|
|
|
Get flows (and other parameters) from h2oline.com sites |
|
3
|
|
|
""" |
|
4
|
|
|
import datetime |
|
5
|
|
|
import logging |
|
6
|
|
|
import re |
|
7
|
|
|
|
|
8
|
|
|
from bs4 import BeautifulSoup |
|
9
|
|
|
import requests |
|
10
|
|
|
import parsedatetime |
|
11
|
|
|
|
|
12
|
|
|
from app.models import Sensor |
|
13
|
|
|
from .base import add_new_sample, RemoteGage |
|
14
|
|
|
|
|
15
|
|
|
logger = logging.getLogger(__name__) |
|
16
|
|
|
|
|
17
|
|
|
|
|
18
|
|
|
class H2Oline(RemoteGage): |
|
19
|
|
|
@staticmethod |
|
20
|
|
|
def soup(remote_id): |
|
21
|
|
|
""" |
|
22
|
|
|
Return a beautiful soup object from h2oline |
|
23
|
|
|
""" |
|
24
|
|
|
url = 'http://www.h2oline.com/default.aspx?pg=si&op={}'.format(remote_id) |
|
25
|
|
|
r = requests.get(url) |
|
26
|
|
|
return BeautifulSoup(r.text, 'html.parser') |
|
27
|
|
|
|
|
28
|
|
|
def river(self, remote_id, soup=None): |
|
29
|
|
|
""" |
|
30
|
|
|
Return string with river name and location |
|
31
|
|
|
""" |
|
32
|
|
|
if soup is None: |
|
33
|
|
|
soup = self.soup(remote_id) |
|
34
|
|
|
river_strings = soup.body.findAll(text=re.compile(str(remote_id))) |
|
35
|
|
|
return ' '.join(river_strings[0].split()[1:]) |
|
36
|
|
|
|
|
37
|
|
|
def value_strings(self, remote_id, parameter='CFS', soup=None): |
|
38
|
|
|
""" |
|
39
|
|
|
Return strings containing specified parameter |
|
40
|
|
|
""" |
|
41
|
|
|
if soup is None: |
|
42
|
|
|
soup = self.soup(remote_id) |
|
43
|
|
|
p = re.compile('([\d.]+)+(?= {})'.format(parameter)) |
|
44
|
|
|
return soup.body.findAll(text=p) |
|
45
|
|
|
|
|
46
|
|
|
@staticmethod |
|
47
|
|
|
def start_end(string, parameter): |
|
48
|
|
|
""" |
|
49
|
|
|
Return the start and end of the parameter in the string |
|
50
|
|
|
""" |
|
51
|
|
|
p = re.compile('([\d.]+)+(?= {})'.format(parameter)) |
|
52
|
|
|
result = p.search(string) |
|
53
|
|
|
return result.start(), result.end() |
|
54
|
|
|
|
|
55
|
|
|
def value(self, remote_id, parameter='CFS', soup=None): |
|
56
|
|
|
""" |
|
57
|
|
|
Return float of first CFS found |
|
58
|
|
|
If given a parameter string, it will find that instead |
|
59
|
|
|
""" |
|
60
|
|
|
if soup is None: |
|
61
|
|
|
cfs_strings = self.value_strings(remote_id, parameter=parameter) |
|
62
|
|
|
else: |
|
63
|
|
|
cfs_strings = self.value_strings(remote_id, parameter=parameter, soup=soup) |
|
64
|
|
|
start, end = self.start_end(cfs_strings[0], parameter) |
|
65
|
|
|
return float(cfs_strings[0][start:end]) |
|
66
|
|
|
|
|
67
|
|
|
|
|
68
|
|
|
def dt_value(self, remote_id, parameter='CFS', soup=None): |
|
69
|
|
|
""" |
|
70
|
|
|
Returns datetime and float of first CFS (or other parameter) found |
|
71
|
|
|
""" |
|
72
|
|
|
strings = self.value_strings(remote_id, |
|
73
|
|
|
parameter=parameter, |
|
74
|
|
|
soup=soup) |
|
75
|
|
|
start, end = self.start_end(strings[0], parameter) |
|
76
|
|
|
dt = datetime.datetime.now() |
|
77
|
|
|
return dt, float(strings[0][start:end]) |
|
78
|
|
|
|
|
79
|
|
|
def get_sample(self, sensor_id): |
|
80
|
|
|
""" |
|
81
|
|
|
Takes a sensor id, tries to get the latest sample from the site |
|
82
|
|
|
""" |
|
83
|
|
|
sensor = self.sensor(sensor_id) |
|
84
|
|
|
if sensor.remote_parameter is None: |
|
85
|
|
|
dt, v = self.dt_value(sensor.remote_id) |
|
86
|
|
|
else: |
|
87
|
|
|
dt, v = self.dt_value(sensor.remote_id, |
|
88
|
|
|
parameter=sensor.remote_parameter) |
|
89
|
|
|
add_new_sample(sensor.id, dt, v) |
|
90
|
|
|
|