Fix test data, more test views
parent
e8245ceb6b
commit
5358c3af49
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
# Populating with test data
|
||||
|
||||
Truncate all data: `python manage.py flush datavis`
|
||||
|
||||
Reset database (normal sql client):
|
||||
```sql
|
||||
DROP DATABASE SouthwestChickenTest;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import datetime
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.utils import timezone
|
||||
from datavis.models import *
|
||||
|
||||
import datetime
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Initialize database with test data"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument("part", nargs="+", type=int)
|
||||
# parser.add_argument("part", nargs="+", type=int)
|
||||
pass
|
||||
|
||||
@transaction.atomic
|
||||
|
|
@ -17,14 +17,30 @@ class Command(BaseCommand):
|
|||
try:
|
||||
with transaction.atomic():
|
||||
try:
|
||||
self.stdout.write(
|
||||
self.style.NOTICE("Adding base data")
|
||||
)
|
||||
self.add_base_data()
|
||||
except Exception as e:
|
||||
raise CommandError("Failed to add base data", e)
|
||||
try:
|
||||
self.stdout.write(
|
||||
self.style.NOTICE("Adding Robot Hands data")
|
||||
)
|
||||
self.add_robot_hands_groups()
|
||||
except Exception as e:
|
||||
raise CommandError("Failed to add robot hands group", e)
|
||||
try:
|
||||
self.stdout.write(
|
||||
self.style.NOTICE("Adding demo site")
|
||||
)
|
||||
self.add_demo_site()
|
||||
except Exception as e:
|
||||
raise CommandError("Failed to add demo turkey site", e)
|
||||
try:
|
||||
self.stdout.write(
|
||||
self.style.NOTICE("Adding virtual site")
|
||||
)
|
||||
self.add_virtual_site()
|
||||
except Exception as e:
|
||||
raise CommandError("Failed to add virtual site data", e)
|
||||
|
|
@ -34,7 +50,21 @@ class Command(BaseCommand):
|
|||
self.style.SUCCESS("Successfully generated sample data")
|
||||
)
|
||||
|
||||
def add_base_data(self):
|
||||
group_types = [
|
||||
"Site",
|
||||
"Windrow",
|
||||
"Temperature Site"
|
||||
]
|
||||
|
||||
for group_type_name in group_types:
|
||||
group_type = GroupType()
|
||||
group_type.name = group_type_name
|
||||
group_type.save()
|
||||
|
||||
def add_robot_hands_groups(self):
|
||||
group_types = GroupType.objects.all()
|
||||
|
||||
"""
|
||||
Site: "Wisconsin Turkey"
|
||||
- [ ] Windrows: 2 Windrows
|
||||
|
|
@ -43,47 +73,106 @@ class Command(BaseCommand):
|
|||
robot_hands = Group()
|
||||
robot_hands.name = "Robot Hands"
|
||||
robot_hands.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = robot_hands
|
||||
group_type.type = group_types.get(name="Site")
|
||||
group_type.save()
|
||||
|
||||
incomplete_probes = Group()
|
||||
incomplete_probes.name = "Incomplete Probes"
|
||||
incomplete_probes.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = incomplete_probes
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
|
||||
incomplete_base_stations = Group()
|
||||
incomplete_base_stations.name = "Incomplete Base Stations"
|
||||
incomplete_base_stations.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = incomplete_base_stations
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
|
||||
complete_probes = Group()
|
||||
complete_probes.name = "Probes Ready To Deploy"
|
||||
complete_probes.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = complete_probes
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
|
||||
complete_base_stations = Group()
|
||||
complete_base_stations.name = "Base Stations Ready To Deploy"
|
||||
complete_base_stations.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = complete_base_stations
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
|
||||
def add_demo_site(self):
|
||||
group_types = GroupType.objects.all()
|
||||
|
||||
demo_site = Group()
|
||||
demo_site.name = "Wisconsin Turkey"
|
||||
demo_site.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = demo_site
|
||||
group_type.type = group_types.get(name="Site")
|
||||
group_type.save()
|
||||
|
||||
windrow_1 = Group()
|
||||
windrow_1.name = "Windrow 1"
|
||||
windrow_1.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = windrow_1
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = demo_site
|
||||
group_parent.child = windrow_1
|
||||
group_parent.save()
|
||||
|
||||
windrow_2 = Group()
|
||||
windrow_2.name = "Windrow 2"
|
||||
windrow_2.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = windrow_2
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = demo_site
|
||||
group_parent.child = windrow_1
|
||||
group_parent.save()
|
||||
|
||||
for i in range(10):
|
||||
temperature_site = Group()
|
||||
temperature_site.name = f"{windrow_1.name} - Site {i+1}"
|
||||
temperature_site.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = temperature_site
|
||||
group_type.type = group_types.get(name="Temperature Site")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = windrow_1
|
||||
group_parent.child = temperature_site
|
||||
group_parent.save()
|
||||
|
||||
for i in range(10):
|
||||
temperature_site = Group()
|
||||
temperature_site.name = f"{windrow_2.name} - Site {i+1}"
|
||||
temperature_site.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = temperature_site
|
||||
group_type.type = group_types.get(name="Temperature Site")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = windrow_2
|
||||
group_parent.child = temperature_site
|
||||
group_parent.save()
|
||||
|
||||
def add_virtual_site(self):
|
||||
group_types = GroupType.objects.all()
|
||||
"""
|
||||
10 virtual nodes
|
||||
- [ ] 1 virtual base station
|
||||
|
|
@ -95,10 +184,22 @@ class Command(BaseCommand):
|
|||
virtual_site = Group()
|
||||
virtual_site.name = "Virtual Site"
|
||||
virtual_site.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = virtual_site
|
||||
group_type.type = group_types.get(name="Site")
|
||||
group_type.save()
|
||||
|
||||
windrow_1 = Group()
|
||||
windrow_1.name = "Windrow 1"
|
||||
windrow_1.save()
|
||||
group_type = Group2Type()
|
||||
group_type.group = windrow_1
|
||||
group_type.type = group_types.get(name="Windrow")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = virtual_site
|
||||
group_parent.child = windrow_1
|
||||
group_parent.save()
|
||||
|
||||
temperature_sites: list[Group] = []
|
||||
for i in range(10):
|
||||
|
|
@ -106,11 +207,23 @@ class Command(BaseCommand):
|
|||
temperature_site.name = f"{windrow_1.name} - Site {i+1}"
|
||||
temperature_site.save()
|
||||
temperature_sites.append(temperature_site)
|
||||
group_type = Group2Type()
|
||||
group_type.group = temperature_site
|
||||
group_type.type = group_types.get(name="Temperature Site")
|
||||
group_type.save()
|
||||
group_parent = GroupParent()
|
||||
group_parent.parent = windrow_1
|
||||
group_parent.child = temperature_site
|
||||
group_parent.save()
|
||||
|
||||
virtual_base_station = Node()
|
||||
virtual_base_station.friendly_name = "Virtual Base Station 1"
|
||||
virtual_base_station.hardware_id = "1"
|
||||
virtual_base_station.save()
|
||||
node_group = Node2Group()
|
||||
node_group.node = virtual_base_station
|
||||
node_group.group = windrow_1
|
||||
node_group.save()
|
||||
|
||||
NUM_VIRTUAL_NODES = 10
|
||||
created_nodes: list[Node] = []
|
||||
|
|
@ -120,6 +233,11 @@ class Command(BaseCommand):
|
|||
virtual_node.save()
|
||||
created_nodes.append(virtual_node)
|
||||
|
||||
node_group = Node2Group()
|
||||
node_group.node = virtual_node
|
||||
node_group.group = temperature_sites[i]
|
||||
node_group.save()
|
||||
|
||||
SAMPLES_PER_DAY = 4
|
||||
NUMBER_OF_DAYS = 14
|
||||
for i in range(SAMPLES_PER_DAY * NUMBER_OF_DAYS):
|
||||
|
|
@ -129,9 +247,9 @@ class Command(BaseCommand):
|
|||
measurement.reporting_node = virtual_base_station
|
||||
measurement.associated_group = temperature_sites[node_index]
|
||||
# Every 6 hours
|
||||
measurement.collection_time = datetime.datetime.now() + datetime.timedelta(seconds=6 * 3600 * i)
|
||||
measurement.collection_time = timezone.now() + datetime.timedelta(seconds=6 * 3600 * i)
|
||||
# Slight offset
|
||||
measurement.server_received_time = datetime.datetime.now() + datetime.timedelta(seconds=6.25 * 3600 * i)
|
||||
measurement.server_received_time = timezone.now() + datetime.timedelta(seconds=6.25 * 3600 * i)
|
||||
measurement.probe_temperature = 1.0
|
||||
measurement.temperature_18_inch = 1.0
|
||||
measurement.temperature_36_inch = 1.0
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import logging
|
||||
|
||||
from .models import Group, GroupParent, Node, Node2Group
|
||||
from .models import Group, GroupParent, Node, Node2Group, Measurement
|
||||
|
||||
|
||||
def get_child_nodes(parent: Group):
|
||||
relationships = list(GroupParent.objects.all())
|
||||
|
|
@ -19,6 +20,10 @@ def get_child_nodes(parent: Group):
|
|||
|
||||
return result
|
||||
|
||||
def get_sites_for_user():
|
||||
site_candidates = Group.objects.filter(group2type__type__name="Site")
|
||||
return site_candidates
|
||||
|
||||
def get_customer_site_application_data(site_id: int) -> dict | None :
|
||||
"""
|
||||
Composes relationships into logical application format, for a given customer
|
||||
|
|
@ -71,7 +76,8 @@ def get_customer_site_application_data(site_id: int) -> dict | None :
|
|||
"id": t_site.pk,
|
||||
"parent_windrow": windrow.pk,
|
||||
"assigned_probe": None if len(nodes) == 0 else nodes[0],
|
||||
"measurements": []
|
||||
# TODO: Don't do N queries? Or is it cached effectively
|
||||
"measurements": Measurement.objects.filter(associated_group=t_site)
|
||||
}
|
||||
else:
|
||||
logging.fatal("Invariant not upheld: Multiple nodes in temperature site")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "datavis/index.html" %} {% block content %}
|
||||
<main>
|
||||
<article>
|
||||
<h1>All Sites</h1>
|
||||
|
||||
<section class="flex gap-3">
|
||||
<section class="flex-1">
|
||||
{% for site in available_sites %}
|
||||
|
||||
<a href="{{site.id}}">{{site.name}}</a>
|
||||
|
||||
{% endfor %}
|
||||
</section>
|
||||
</section>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
|
|
@ -1,13 +1,13 @@
|
|||
{% extends "datavis/index.html" %} {% block content %}
|
||||
<main>
|
||||
<article>
|
||||
<h1>Site - {{customer.site.name}}</h1>
|
||||
<h1 class="text-2xl font-bold">Site - {{customer.site.name}}</h1>
|
||||
|
||||
<section class="flex gap-3">
|
||||
<section class="flex-1">
|
||||
{% for windrow_id, windrow in customer.windrows.items %}
|
||||
|
||||
<a href="?row={{windrow_id}}"{% if windrow_id == selected_windrow.id %}class="font-bold"{% endif %}>{{windrow.name}}</a>
|
||||
<a class="text-blue-500 underline cursor-pointer hover:text-blue-400" href="?row={{windrow_id}}"{% if windrow_id == selected_windrow.id %}class="font-bold"{% endif %}>{{windrow.name}}</a>
|
||||
|
||||
{% endfor %}
|
||||
</section>
|
||||
|
|
@ -16,13 +16,15 @@
|
|||
<a href="?row={{temp_site.parent_windrow}}&temp_site={{temp_site.id}}">{{temp_site.name}}</a>
|
||||
{% endfor %}
|
||||
</section>
|
||||
<section class="flex-1">
|
||||
{{selected_temperature_site.assigned_probe.friendly_name}}
|
||||
{{selected_temperature_site.measurements}}
|
||||
</section>
|
||||
<!-- <section class="flex-1">-->
|
||||
<!-- {{selected_temperature_site.assigned_probe.friendly_name}}-->
|
||||
<!-- {{selected_temperature_site.measurements}}-->
|
||||
<!-- </section>-->
|
||||
<section class="flex-1"></section>
|
||||
</section>
|
||||
|
||||
{% if selected_temperature_site %}
|
||||
<h2 class="text-xl font-bold">{{selected_temperature_site.name}}</h2>
|
||||
<table
|
||||
class="w-full text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400"
|
||||
>
|
||||
|
|
@ -38,33 +40,27 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody class="">
|
||||
{% for measurement in measurements %}
|
||||
{% for measurement in selected_temperature_site.measurements %}
|
||||
<tr
|
||||
class="bg-white border-b dark:bg-gray-800 dark:border-gray-700 border-gray-200 hover:bg-gray-50 dark:hover:bg-gray-600"
|
||||
>
|
||||
<td
|
||||
class="px-6 py-4 font-medium text-gray-900 whitespace-nowrap dark:text-white"
|
||||
>
|
||||
{{measurement.received_time}}
|
||||
{{measurement.collection_time}}
|
||||
</td>
|
||||
<td class="px-6 py-4">{{measurement.device_id}}</td>
|
||||
<td class="px-6 py-4">{{measurement.temp18}} C</td>
|
||||
<td class="px-6 py-4">{{measurement.source_node.friendly_name}}</td>
|
||||
<td class="px-6 py-4">{{measurement.temperature_18_inch}} C</td>
|
||||
<td class="px-6 py-4">
|
||||
{{measurement.ambient_temperature}} C
|
||||
</td>
|
||||
<td class="px-6 py-4">{{measurement.battery_voltage}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</article>
|
||||
<article>
|
||||
<h1>Graphics</h1>
|
||||
<section>
|
||||
<svg viewBox="0 0 500 500">
|
||||
<rect x="0" width="500" y="0" height="500" fill="#aaa" />
|
||||
</svg>
|
||||
</section>
|
||||
{% endif %}
|
||||
</article>
|
||||
</main>
|
||||
{% endblock content %}
|
||||
|
|
|
|||
|
|
@ -5,5 +5,6 @@ from . import views
|
|||
urlpatterns = [
|
||||
path("", views.index, name="dashboard_home"),
|
||||
path("livedemo", views.guest_demo, name="livedemo"),
|
||||
path("site/<int:site_id>", views.site_view, name="site_view")
|
||||
path("sites/", views.all_sites, name="all_sites"),
|
||||
path("sites/<int:site_id>", views.site_view, name="site_view")
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
from zoneinfo import available_timezones
|
||||
|
||||
from django.shortcuts import render
|
||||
|
||||
from .model_util import get_customer_site_application_data
|
||||
from .model_util import get_customer_site_application_data, get_sites_for_user
|
||||
|
||||
from .models import Measurement
|
||||
from .models import Measurement, Group
|
||||
|
||||
# Create your views here.
|
||||
def index(request):
|
||||
|
|
@ -22,6 +24,15 @@ def guest_demo(request):
|
|||
|
||||
return render(request, "datavis/dashboard_home.html", context)
|
||||
|
||||
def all_sites(request):
|
||||
if request.method == "GET":
|
||||
context = {
|
||||
"available_sites": get_sites_for_user(),
|
||||
}
|
||||
return render(request, "datavis/all_sites.html", context)
|
||||
|
||||
return None
|
||||
|
||||
def site_view(request, site_id):
|
||||
|
||||
customer_data = get_customer_site_application_data(site_id)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,6 @@ from django.urls import include, path
|
|||
|
||||
urlpatterns = [
|
||||
path('', include("marketing.urls")),
|
||||
path('dashboard/', include("datavis.urls")),
|
||||
path('inspect/', include("datavis.urls")),
|
||||
path('admin/', admin.site.urls),
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue