Commit f117fdd95d4da2bdf0dbbe9004e083d6f3052fbb
1 parent
c5ae1cae
Exists in
dev
PLC STATE + MODE
Showing
7 changed files
with
95 additions
and
20 deletions
Show diff stats
src/common/models.py
... | ... | @@ -53,7 +53,7 @@ class Device(models.Model): |
53 | 53 | |
54 | 54 | class PlcDeviceStatus(models.Model): |
55 | 55 | device = models.ForeignKey('PlcDevice', on_delete=models.CASCADE, related_name='current_status') |
56 | - | |
56 | + created = models.DateTimeField(auto_now_add=True, editable=False, blank=True) | |
57 | 57 | outside_temp = models.DecimalField(max_digits=15, decimal_places=8, blank=True, null=True) |
58 | 58 | outside_temp_unit = models.CharField(max_length=45, blank=True, null=True) |
59 | 59 | outside_humidity = models.DecimalField(max_digits=15, decimal_places=8, blank=True, null=True) |
... | ... | @@ -85,6 +85,8 @@ class PlcDeviceStatus(models.Model): |
85 | 85 | status = models.CharField(max_length=45, blank=True, null=True) |
86 | 86 | current = models.DecimalField(max_digits=15, decimal_places=8, blank=True, null=True) |
87 | 87 | current_unit = models.CharField(max_length=45, blank=True, null=True) |
88 | + is_safe = models.BooleanField(default=False) | |
89 | + plc_mode = models.CharField(max_length=4, null=True) | |
88 | 90 | |
89 | 91 | class Meta: |
90 | 92 | managed = True |
... | ... | @@ -146,6 +148,10 @@ class PlcDeviceStatus(models.Model): |
146 | 148 | elif key == "current": |
147 | 149 | self.current = value |
148 | 150 | self.current_unit = unit |
151 | + elif key == "mode": | |
152 | + self.plc_mode = value | |
153 | + elif key == "is_safe": | |
154 | + self.is_safe = value | |
149 | 155 | else: |
150 | 156 | raise KeyError("Key " + str(key) + " unrecognized") |
151 | 157 | |
... | ... | @@ -155,8 +161,7 @@ class PlcDevice(Device): |
155 | 161 | desc = models.TextField(blank=True, null=True) |
156 | 162 | created = models.DateTimeField(blank=True, null=True, auto_now_add=True) |
157 | 163 | updated = models.DateTimeField(blank=True, null=True, auto_now=True) |
158 | - is_safe = models.BooleanField(default=True) | |
159 | - plc_mode = models.CharField(max_length=4, null=True) | |
164 | + | |
160 | 165 | |
161 | 166 | class Meta: |
162 | 167 | managed = True | ... | ... |
src/dashboard/templates/dashboard/index.html
... | ... | @@ -99,13 +99,7 @@ |
99 | 99 | <a href="{% url "weather" %}"> |
100 | 100 | <div class="all-info"> |
101 | 101 | <h3>Weather</h3> |
102 | - {% if weather_img == "red" %} | |
103 | - <img src="{% static "media/weather_red.png" %}" alt="html5" height="200" width="200"/> | |
104 | - {% elif weather_img == "orange" %} | |
105 | - <img src="{% static "media/weather_orange.png" %}" alt="html5" height="200" width="200"/> | |
106 | - {% else %} | |
107 | - <img src="{% static "media/weather.png" %}" alt="html5" height="200" width="200"/> | |
108 | - {% endif %} | |
102 | + <img id="weather_big_img" src="{% static "media/weather.png" %}" alt="html5" height="200" width="200"/> | |
109 | 103 | </div></a> |
110 | 104 | </div> |
111 | 105 | </li> |
... | ... | @@ -115,7 +109,7 @@ |
115 | 109 | <a href="{% url "states" %}"> |
116 | 110 | <div class="all-info"> |
117 | 111 | <h3>Observatory</h3> |
118 | - <img src="{% static "media/state.png" %}" alt="html5" height="200" width="200"/> | |
112 | + <img id="observatory_img" src="{% static "media/state.png" %}" alt="html5" height="200" width="200"/> | |
119 | 113 | </div></a> |
120 | 114 | </div> |
121 | 115 | </li> |
... | ... | @@ -210,4 +204,44 @@ |
210 | 204 | </div> |
211 | 205 | </div> |
212 | 206 | </section> |
213 | -{% endblock %} | |
214 | 207 | \ No newline at end of file |
208 | +<script> | |
209 | + var REFRESH_ICONS_FREQUENCE_MILLISECONDS = 1000; | |
210 | + | |
211 | + $( document ).ready(function() { | |
212 | + | |
213 | + ajax_reload(); | |
214 | + interval = setInterval(function() {ajax_reload();}, REFRESH_ICONS_FREQUENCE_MILLISECONDS); | |
215 | + | |
216 | + function ajax_reload() { | |
217 | + $.get("{% url 'retrieve_main_icon' %}", function (weather_status) { | |
218 | + if (weather_status) | |
219 | + { | |
220 | + var _img_weather = document.createElement('img'); | |
221 | + if (weather_status[0]['fields']['global_status'].startsWith("RAINING")) | |
222 | + _img_weather.src = "{% static 'media/weather_red.png' %}"; | |
223 | + else | |
224 | + _img_weather.src = "{% static 'media/weather.png' %}"; | |
225 | + _img_weather.width = 200; | |
226 | + _img_weather.height = 200; | |
227 | + _img_weather.id ="weather_big_img"; | |
228 | + _img_weather.alt = "html5"; | |
229 | + $("#weather_big_img").replaceWith(_img_weather); | |
230 | + | |
231 | + var _img_observatory = document.createElement('img'); | |
232 | + if (weather_status[0]['plc_mode'].startsWith("AUTO")) | |
233 | + _img_observatory.src = "{% static 'media/observatory.png' %}"; | |
234 | + else | |
235 | + _img_observatory.src = "{% static 'media/observatory_red.png' %}"; | |
236 | + _img_observatory.width = 200; | |
237 | + _img_observatory.height = 200; | |
238 | + _img_observatory.id ="observatory_img"; | |
239 | + _img_observatory.alt = "html5"; | |
240 | + $("#observatory_img").replaceWith(_img_observatory); | |
241 | + } | |
242 | + }, 'json') | |
243 | + .fail(function () { | |
244 | + console.log('Ajax error: GET request failed\n'); | |
245 | + }) | |
246 | + }}); | |
247 | + </script> | |
248 | +{% endblock %} | |
215 | 249 | \ No newline at end of file | ... | ... |
src/dashboard/urls.py
... | ... | @@ -29,4 +29,5 @@ urlpatterns = [ |
29 | 29 | path('users/<int:pk>/edit', views.user_detail_edit, name='user-edit'), |
30 | 30 | path('user-status/<int:pk>', views.change_activate, name='change_activate'), |
31 | 31 | path('states', views.operator_state, name='states'), |
32 | + path('retrieve_main_icon', views.retrieve_main_icon, name='retrieve_main_icon') | |
32 | 33 | ] | ... | ... |
src/dashboard/views.py
... | ... | @@ -3,7 +3,7 @@ from django.shortcuts import render, redirect |
3 | 3 | |
4 | 4 | from django.contrib.auth.decorators import login_required |
5 | 5 | import datetime |
6 | -from common.models import Log, WeatherWatch, SiteWatch, ScientificProgram, Config, PyrosUser | |
6 | +from common.models import Log, WeatherWatch, SiteWatch, ScientificProgram, Config, PyrosUser, PlcDeviceStatus | |
7 | 7 | from django.core import serializers |
8 | 8 | import utils.Logger as l |
9 | 9 | from django.forms import modelformset_factory |
... | ... | @@ -46,9 +46,25 @@ def retrieve_env_navbar(request): |
46 | 46 | if request.is_ajax(): |
47 | 47 | try: |
48 | 48 | weather_status = WeatherWatch.objects.latest('updated') |
49 | + plc_mode = PlcDeviceStatus.objects.latest('created').plc_mode | |
50 | + is_safe = PlcDeviceStatus.objects.latest('created').is_safe | |
49 | 51 | weather = serializers.serialize('json', [weather_status]) |
50 | 52 | weather = json.loads(weather) |
51 | 53 | weather[0]['sunelev'] = randint(-30, 30) #remplacer par l'appel au code d'Alain quand il sera dispo |
54 | + weather[0]["plc_mode"] = plc_mode | |
55 | + weather[0]["is_safe"] = is_safe | |
56 | + return HttpResponse(json.dumps(weather), content_type="application/json") | |
57 | + except WeatherWatch.DoesNotExist: | |
58 | + raise Http404("No WeatherWatch matches the given query.") | |
59 | + | |
60 | +def retrieve_main_icon(request): | |
61 | + if request.is_ajax(): | |
62 | + try: | |
63 | + weather_status = WeatherWatch.objects.latest('updated') | |
64 | + plc_mode = PlcDeviceStatus.objects.latest('created').plc_mode | |
65 | + weather = serializers.serialize('json', [weather_status]) | |
66 | + weather = json.loads(weather) | |
67 | + weather[0]["plc_mode"] = plc_mode | |
52 | 68 | return HttpResponse(json.dumps(weather), content_type="application/json") |
53 | 69 | except WeatherWatch.DoesNotExist: |
54 | 70 | raise Http404("No WeatherWatch matches the given query.") | ... | ... |
src/misc/fixtures/initial_fixture.json
src/misc/templates/base.html
... | ... | @@ -76,6 +76,12 @@ a { |
76 | 76 | font-size: 14px; |
77 | 77 | } |
78 | 78 | |
79 | +#plc_state | |
80 | +{ | |
81 | + color: white; | |
82 | + font-size: 18px; | |
83 | +} | |
84 | + | |
79 | 85 | #signout { |
80 | 86 | color: black; |
81 | 87 | } |
... | ... | @@ -129,7 +135,7 @@ a { |
129 | 135 | <li><a href="#">Images</a></li> |
130 | 136 | </ul> |
131 | 137 | <ul class="nav navbar-nav navbar-right navbar-user"> |
132 | - <li id="plc_state"></li> | |
138 | + <li><a id="plc_state"></a></li> | |
133 | 139 | <li><a class="nav-brand" id="hour">Sun elevation :</a></li> |
134 | 140 | <li><a class="nav-brand" id="day_night" href="{% url "weather" %}"><img id="day_night_img"></a></li> |
135 | 141 | <li><a class="nav-brand" id="wind" href="{% url "weather" %}"><img id="wind_img"></a></li> |
... | ... | @@ -167,6 +173,15 @@ a { |
167 | 173 | color = "#6b69f3"; |
168 | 174 | $("#topbar").css("background-color", color); |
169 | 175 | } |
176 | + function info_plc(is_safe, mode) | |
177 | + { | |
178 | + var safe = "UNSAFE"; | |
179 | + if (is_safe) | |
180 | + safe = "SAFE"; | |
181 | + | |
182 | + $("#plc_state").text("PLC: " + mode + " " + safe); | |
183 | + } | |
184 | + | |
170 | 185 | ajax_request(); |
171 | 186 | interval = setInterval(function() {ajax_request();}, REFRESH_ICONS_FREQUENCE_MILLISECONDS); |
172 | 187 | |
... | ... | @@ -218,6 +233,7 @@ a { |
218 | 233 | set_elev(weather_status[0]['sunelev']); |
219 | 234 | change_color(parseInt(weather_status[0]['sunelev'])); |
220 | 235 | console.log(weather_status); |
236 | + info_plc(weather_status[0]["is_safe"], weather_status[0]["plc_mode"]); | |
221 | 237 | } |
222 | 238 | }, 'json') |
223 | 239 | .fail(function () { | ... | ... |
src/monitoring/tasks.py
... | ... | @@ -160,14 +160,16 @@ class Monitoring(Task): |
160 | 160 | def extractFromDict(self, status): |
161 | 161 | synthesis = {} |
162 | 162 | devices = status["device"] |
163 | + is_safe_str = status["is_safe"] | |
164 | + mode = status["mode"] | |
163 | 165 | for device in devices: |
164 | 166 | for value in device["values"]: |
165 | 167 | synthesis[value["name"]] = value["value"] |
166 | 168 | synthesis[value["name"] + "_unit"] = value["unit"] |
167 | - return synthesis | |
169 | + return synthesis,is_safe_str, mode | |
168 | 170 | |
169 | 171 | # TODO ATTENTION SI DEUX DEVICES ONT LE MEME NOM |
170 | - def saveContent(self, content): | |
172 | + def saveContent(self, content, is_safe_str, mode): | |
171 | 173 | devices = content["device"] |
172 | 174 | for device in devices: |
173 | 175 | status = PlcDeviceStatus() |
... | ... | @@ -179,6 +181,9 @@ class Monitoring(Task): |
179 | 181 | status.device = database_device |
180 | 182 | for value in device["values"]: |
181 | 183 | status.setValue(value["name"], value["value"], value["unit"]) |
184 | + | |
185 | + status.setValue("mode", mode) | |
186 | + status.setValue("is_safe", is_safe_str) | |
182 | 187 | status.save() |
183 | 188 | |
184 | 189 | ''' |
... | ... | @@ -190,8 +195,8 @@ class Monitoring(Task): |
190 | 195 | dict = json.loads(status_plc)[0] |
191 | 196 | if dict["name"] == "STATUS": |
192 | 197 | if self.isStatusValid(): |
193 | - status = self.extractFromDict(dict) | |
194 | - self.saveContent(dict) | |
198 | + status, is_safe_str, mode = self.extractFromDict(dict) | |
199 | + self.saveContent(dict, is_safe_str, mode) | |
195 | 200 | else: |
196 | 201 | # TODO HANDLE ERROR HERE |
197 | 202 | pass | ... | ... |