Update models and db config

main
ookjosh 2025-12-08 23:31:43 -07:00
parent ffc7a6254e
commit 9291563cd1
3 changed files with 141 additions and 18 deletions

View File

@ -2,6 +2,7 @@ from django.core.management.base import BaseCommand, CommandError
from django.db import transaction, IntegrityError
from django.utils import timezone
from datavis.models import *
from django.contrib.auth.models import User
import datetime
@ -57,138 +58,173 @@ class Command(BaseCommand):
"Temperature Site"
]
author = User.objects.all()[0]
for group_type_name in group_types:
group_type = GroupType()
group_type.author = author
group_type.name = group_type_name
group_type.save()
def add_robot_hands_groups(self):
group_types = GroupType.objects.all()
author = User.objects.all()[0]
"""
Site: "Wisconsin Turkey"
- [ ] Windrows: 2 Windrows
- [ ] 10 temperature sites each
"""
robot_hands = Group()
robot_hands.author = author
robot_hands.name = "Robot Hands"
robot_hands.save()
group_type = Group2Type()
group_type.author = author
group_type.group = robot_hands
group_type.type = group_types.get(name="Site")
group_type.save()
incomplete_probes = Group()
incomplete_probes.author = author
incomplete_probes.name = "Incomplete Probes"
incomplete_probes.save()
group_type = Group2Type()
group_type.author = author
group_type.group = incomplete_probes
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = robot_hands
group_parent.child = incomplete_probes
group_parent.save()
incomplete_base_stations = Group()
incomplete_base_stations.author = author
incomplete_base_stations.name = "Incomplete Base Stations"
incomplete_base_stations.save()
group_type = Group2Type()
group_type.author = author
group_type.group = incomplete_base_stations
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = robot_hands
group_parent.child = incomplete_base_stations
group_parent.save()
complete_probes = Group()
complete_probes.author = author
complete_probes.name = "Probes Ready To Deploy"
complete_probes.save()
group_type = Group2Type()
group_type.author = author
group_type.group = complete_probes
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = robot_hands
group_parent.child = complete_probes
group_parent.save()
complete_base_stations = Group()
complete_base_stations.author = author
complete_base_stations.name = "Base Stations Ready To Deploy"
complete_base_stations.save()
group_type = Group2Type()
group_type.author = author
group_type.group = complete_base_stations
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = robot_hands
group_parent.child = complete_base_stations
group_parent.save()
def add_demo_site(self):
group_types = GroupType.objects.all()
author = User.objects.all()[0]
demo_site = Group()
demo_site.author = author
demo_site.name = "Wisconsin Turkey"
demo_site.save()
group_type = Group2Type()
group_type.author = author
group_type.group = demo_site
group_type.type = group_types.get(name="Site")
group_type.save()
windrow_1 = Group()
windrow_1.author = author
windrow_1.name = "Windrow 1"
windrow_1.save()
group_type = Group2Type()
group_type.author = author
group_type.group = windrow_1
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = demo_site
group_parent.child = windrow_1
group_parent.save()
windrow_2 = Group()
windrow_2.author = author
windrow_2.name = "Windrow 2"
windrow_2.save()
group_type = Group2Type()
group_type.author = author
group_type.group = windrow_2
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = demo_site
group_parent.child = windrow_1
group_parent.save()
for i in range(10):
temperature_site = Group()
temperature_site.author = author
temperature_site.name = f"{windrow_1.name} - Site {i+1}"
temperature_site.save()
group_type = Group2Type()
group_type.author = author
group_type.group = temperature_site
group_type.type = group_types.get(name="Temperature Site")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = windrow_1
group_parent.child = temperature_site
group_parent.save()
for i in range(10):
temperature_site = Group()
temperature_site.author = author
temperature_site.name = f"{windrow_2.name} - Site {i+1}"
temperature_site.save()
group_type = Group2Type()
group_type.author = author
group_type.group = temperature_site
group_type.type = group_types.get(name="Temperature Site")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = windrow_2
group_parent.child = temperature_site
group_parent.save()
def add_virtual_site(self):
group_types = GroupType.objects.all()
author = User.objects.all()[0]
"""
10 virtual nodes
- [ ] 1 virtual base station
@ -198,21 +234,26 @@ class Command(BaseCommand):
- [ ] 2 weeks of sample data for all nodes
"""
virtual_site = Group()
virtual_site.author = author
virtual_site.name = "Virtual Site"
virtual_site.save()
group_type = Group2Type()
group_type.author = author
group_type.group = virtual_site
group_type.type = group_types.get(name="Site")
group_type.save()
windrow_1 = Group()
windrow_1.author = author
windrow_1.name = "Windrow 1"
windrow_1.save()
group_type = Group2Type()
group_type.author = author
group_type.group = windrow_1
group_type.type = group_types.get(name="Windrow")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = virtual_site
group_parent.child = windrow_1
group_parent.save()
@ -220,23 +261,28 @@ class Command(BaseCommand):
temperature_sites: list[Group] = []
for i in range(10):
temperature_site = Group()
temperature_site.author = author
temperature_site.name = f"{windrow_1.name} - Site {i+1}"
temperature_site.save()
temperature_sites.append(temperature_site)
group_type = Group2Type()
group_type.author = author
group_type.group = temperature_site
group_type.type = group_types.get(name="Temperature Site")
group_type.save()
group_parent = GroupParent()
group_parent.author = author
group_parent.parent = windrow_1
group_parent.child = temperature_site
group_parent.save()
virtual_base_station = Node()
virtual_base_station.author = author
virtual_base_station.friendly_name = "Virtual Base Station 1"
virtual_base_station.hardware_id = "1"
virtual_base_station.save()
node_group = Node2Group()
node_group.author = author
node_group.node = virtual_base_station
node_group.group = windrow_1
node_group.save()
@ -245,11 +291,13 @@ class Command(BaseCommand):
created_nodes: list[Node] = []
for i in range(NUM_VIRTUAL_NODES):
virtual_node = Node()
virtual_node.author = author
virtual_node.friendly_name = f"Virtual Probe {i + 1}"
virtual_node.save()
created_nodes.append(virtual_node)
node_group = Node2Group()
node_group.author = author
node_group.node = virtual_node
node_group.group = temperature_sites[i]
node_group.save()

View File

@ -1,19 +1,30 @@
from django.db import models
from django.contrib.auth.models import User
class Node(models.Model):
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
friendly_name = models.CharField(max_length = 255)
hardware_id = models.CharField(max_length = 128)
def __str__(self):
return f"{self.friendly_name} - {self.hardware_id}"
class Group(models.Model):
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length = 255)
def __str__(self):
return self.name
class Node2Group(models.Model):
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
node = models.ForeignKey(to=Node, on_delete=models.CASCADE)
group = models.ForeignKey(to=Group, on_delete=models.CASCADE)
@ -24,6 +35,9 @@ class GroupType (models.Model):
"""
Application-level discriminating field for what a "group" is
"""
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
name = models.CharField(max_length = 255)
def __str__(self):
@ -35,6 +49,9 @@ class GroupParent(models.Model):
TODO: Enforce child != parent
"""
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
child = models.ForeignKey(to=Group, on_delete=models.CASCADE, related_name='child_group')
parent = models.ForeignKey(to=Group, on_delete=models.CASCADE, related_name='parent_group')
@ -42,6 +59,9 @@ class GroupParent(models.Model):
return f"{self.child.name}<{self.parent.name}"
class Group2Type(models.Model):
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
creation_time = models.DateTimeField(auto_now_add=True)
group = models.ForeignKey(to=Group, on_delete=models.CASCADE)
type = models.ForeignKey(to=GroupType, on_delete=models.CASCADE)
@ -60,16 +80,19 @@ class Group2Type(models.Model):
class Measurement(models.Model):
source_node = models.ForeignKey(to=Node, on_delete=models.DO_NOTHING, related_name='measurement_source_node')
collection_time = models.DateTimeField()
server_received_time = models.DateTimeField()
probe_temperature = models.FloatField()
server_received_time = models.DateTimeField(auto_now_add=True)
temperature_18_inch = models.FloatField()
temperature_36_inch = models.FloatField()
ambient_temperature = models.FloatField()
# Onboard ESP32 temperature
device_temperature = models.FloatField()
barometric_pressure = models.FloatField()
# Onboard temp, humidity. Probes:SHTxx, BS: BME280
ambient_temperature = models.FloatField()
relative_humidity = models.FloatField()
# Base station only - BME280
barometric_pressure = models.FloatField()
accelerometer_x = models.FloatField()
accelerometer_y = models.FloatField()
accelerometer_z = models.FloatField()
battery_charge_percent = models.FloatField()
battery_voltage = models.FloatField()
remaining_battery_capacity = models.FloatField()
@ -85,3 +108,55 @@ class Measurement(models.Model):
class Meta:
unique_together = (('source_node', 'collection_time'),)
class NodeRssiRecord(models.Model):
device = models.ForeignKey(to=Node, on_delete=models.DO_NOTHING, related_name='rssi_source_node')
collection_time = models.DateTimeField()
server_received_time = models.DateTimeField(auto_now_add=True)
# Neighbor we heard from
neighbor = models.ForeignKey(to=Node, on_delete=models.DO_NOTHING)
# Signal strength of neighbor from device's perspective
rssi = models.IntegerField()
class NodeFileManifest(models.Model):
device = models.ForeignKey(to=Node, on_delete=models.DO_NOTHING)
collection_time = models.DateTimeField()
server_received_time = models.DateTimeField(auto_now_add=True)
program_id = models.IntegerField()
program_version = models.IntegerField()
class NodeReportedStatus(models.Model):
"""
Status reported by a Node
"""
""" Status 1 """
device = models.ForeignKey(to=Node, on_delete=models.DO_NOTHING)
collection_time = models.DateTimeField()
server_received_time = models.DateTimeField(auto_now_add=True)
measurement_interval_minutes = models.IntegerField()
wake_window_length_minutes = models.IntegerField()
# Default is things are aligned to midnight. This pushes it off that.
offset_from_midnight_minutes = models.IntegerField()
sleep_duration_minutes = models.IntegerField()
""" Status 2 """
# Number of saved measurements on a node
number_saved_measurements = models.IntegerField()
""" Other Things """
when_time_was_last_updated = models.DateTimeField()
class NodeConfiguration(models.Model):
"""
Configuration to be applied to Node(s)
"""
author = models.ForeignKey(to=User, on_delete=models.DO_NOTHING)
created_time = models.DateTimeField(auto_now_add=True)
measurement_interval_minutes = models.IntegerField()
wake_window_length_minutes = models.IntegerField()
# Default is things are aligned to midnight. This pushes it off that.
offset_from_midnight_minutes = models.IntegerField()
sleep_duration_minutes = models.IntegerField()

View File

@ -100,27 +100,27 @@ DATABASES = {
# 'ENGINE': 'django.db.backends.sqlite3',
# 'NAME': BASE_DIR / 'db.sqlite3',
#}
'default': {
"ENGINE": "django.db.backends.mysql",
"OPTIONS": {
#"read_default_file": BASE_DIR.as_posix() + "mysql.cnf",
"read_default_file": "/Users/josh/Documents/ForgejoJed/RobotHands/frontend/mysql.cnf",
},
"HOST": "100.86.33.40",
"PORT": 32768,
}
# DigitalOcean test
# 'default': {
# "ENGINE": "django.db.backends.mysql",
# "OPTIONS": {
# #"read_default_file": BASE_DIR.as_posix() + "mysql.cnf",
# "read_default_file": "/Users/josh/Documents/ForgejoJed/RobotHands/frontend/do_test.cnf",
# "read_default_file": "/Users/josh/Documents/ForgejoJed/RobotHands/frontend/mysql.cnf",
# },
# "HOST": "db-mysql-nyc3-98489-do-user-14777372-0.g.db.ondigitalocean.com",
# "PORT": 25060,
# "HOST": "100.86.33.40",
# "PORT": 32768,
# }
# DigitalOcean test
'default': {
"ENGINE": "django.db.backends.mysql",
"OPTIONS": {
#"read_default_file": BASE_DIR.as_posix() + "mysql.cnf",
"read_default_file": "/Users/josh/Documents/ForgejoJed/RobotHands/frontend/do_test.cnf",
},
"HOST": "rh-data-1-do-user-14777372-0.k.db.ondigitalocean.com",
"PORT": 25060,
}
}
CONN_MAX_AGE = 100