Skip to content

Commit 1206955

Browse files
n11ikNik Sauersilvioheinze
authored
139 label code generieren und im device detail anzeigen (#141)
* added ModelCounter * changed post url back to datahub * changed model filed type to int * added QR-Code Text field * added get_device_name to Device model * format qr-code in device detail * add dev api device initial station info test * create change log for device and user * #84 display logs for Organization, room and user * #143 save when device is saved assign name if model is set * #144 --------- Co-authored-by: Nik Sauer <[email protected]> Co-authored-by: Silvio Heinze <[email protected]>
1 parent 33151b7 commit 1206955

9 files changed

+342
-98
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Generated by Django 5.1.5 on 2025-01-30 10:12
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('devices', '0016_alter_device_current_campaign_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.CreateModel(
14+
name='ModelCounter',
15+
fields=[
16+
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
17+
('model', models.CharField(max_length=255, unique=True)),
18+
('last_auto_number', models.IntegerField(default=0)),
19+
],
20+
),
21+
migrations.AddField(
22+
model_name='device',
23+
name='auto_number',
24+
field=models.IntegerField(blank=True, null=True),
25+
),
26+
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 5.1.5 on 2025-01-30 10:22
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('devices', '0017_modelcounter_device_auto_number'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='modelcounter',
15+
name='id',
16+
),
17+
migrations.AlterField(
18+
model_name='modelcounter',
19+
name='model',
20+
field=models.CharField(max_length=255, primary_key=True, serialize=False),
21+
),
22+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Generated by Django 5.1.5 on 2025-01-30 10:47
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('devices', '0018_remove_modelcounter_id_alter_modelcounter_model'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='device',
15+
name='model',
16+
field=models.IntegerField(blank=True, null=True),
17+
),
18+
migrations.AlterField(
19+
model_name='modelcounter',
20+
name='model',
21+
field=models.IntegerField(primary_key=True, serialize=False),
22+
),
23+
]

app/devices/models.py

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from django.db import models
1+
from django.db import models, transaction
22
from django.utils import timezone
33
from organizations.models import Organization
44
from campaign.models import Room
@@ -7,30 +7,75 @@
77
from auditlog.registry import auditlog
88
from auditlog.models import AuditlogHistoryField
99

10+
from main.enums import LdProduct
11+
1012

1113
class Device(models.Model):
1214
"""
1315
Device model.
1416
"""
1517
id = models.CharField(max_length=255, primary_key=True)
1618
device_name = models.CharField(max_length=255, blank=True, null=True)
17-
model = models.CharField(max_length=255, blank=True, null=True)
19+
model = models.IntegerField(null=True, blank=True)
1820
firmware = models.CharField(max_length=255, blank=True)
1921
btmac_address = models.CharField(max_length=12, null=True, blank=True)
2022
last_update = models.DateTimeField(null=True, blank=True)
2123
notes = models.TextField(null=True, blank=True)
2224
api_key = models.CharField(max_length=64, null=True)
25+
auto_number = models.IntegerField(null=True, blank=True)
2326

2427
current_room = models.ForeignKey(Room, related_name='current_devices', null=True, on_delete=models.SET_NULL, blank=True)
2528
current_organization = models.ForeignKey(Organization, related_name='current_devices', null=True, on_delete=models.SET_NULL, blank=True)
2629
current_user = models.ForeignKey(CustomUser, null=True, related_name='current_devices', on_delete=models.SET_NULL, blank=True)
2730
current_campaign = models.ForeignKey(Campaign, null=True, related_name='current_devices', on_delete=models.SET_NULL, blank=True)
2831

29-
history = AuditlogHistoryField()
32+
history = AuditlogHistoryField(pk_indexable=False)
3033

34+
def save(self, *args, **kwargs):
35+
# if the model id is not set or the auto_number is already set we don't
36+
# need to update the auto_number
37+
if self.model is None:
38+
super().save(*args, **kwargs)
39+
return
40+
41+
if self.auto_number:
42+
# assign name to update existing devices
43+
# TODO could be removed
44+
self.device_name = f'{self.get_model_name()} {self.auto_number:04d}'
45+
super().save(*args, **kwargs)
46+
return
47+
48+
# update auto_number for the first time
49+
with transaction.atomic():
50+
counter, _ = ModelCounter.objects.get_or_create(model=self.model)
51+
counter.last_auto_number += 1
52+
counter.save()
53+
54+
self.auto_number = counter.last_auto_number
55+
'''
56+
assigns a unique name for this device in this format: "{model name}{auto_number}"
57+
for example "Air Cube 0001"
58+
'''
59+
self.device_name = f'{self.get_model_name()} {self.auto_number:04d}'
60+
61+
super().save(*args, **kwargs)
62+
63+
def get_ble_id(self):
64+
# cuts of the 3 last characters that are use for board identification
65+
return self.id[:-3]
66+
67+
def get_model_name(self):
68+
'''returns the corresponding LdProduct name'''
69+
return LdProduct._names.get(self.model, 'Unknown Model')
70+
3171
def __str__(self):
3272
return self.id or "Undefined Device" # Added fallback for undefined IDs
33-
73+
74+
75+
class ModelCounter(models.Model):
76+
model = models.IntegerField(primary_key=True)
77+
last_auto_number = models.IntegerField(default=0)
78+
3479

3580
class Sensor(models.Model):
3681
"""

app/devices/views.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@
1212
from django.db import transaction
1313

1414
from .models import Device, DeviceStatus, DeviceLogs, Measurement
15+
from accounts.models import CustomUser
1516
from .forms import DeviceForm, DeviceNotesForm
1617
from main.enums import SensorModel, Dimension
18+
from organizations.models import Organization
19+
from campaign.models import Room
1720

1821
class DeviceListView(LoginRequiredMixin, UserPassesTestMixin, ListView):
1922
model = Device
@@ -64,6 +67,45 @@ def get_context_data(self, **kwargs):
6467
if status.battery_soc is not None and status.battery_voltage is not None
6568
]
6669

70+
# query changes
71+
organization_changes = device.history.filter(changes__icontains = '"current_organization"').all().order_by('-timestamp')
72+
room_changes = device.history.filter(changes__icontains = '"current_room"').all().order_by('-timestamp')
73+
user_changes = device.history.filter(changes__icontains = '"current_user"').all().order_by('-timestamp')
74+
75+
organization_change_log = []
76+
room_change_log = []
77+
user_change_log = []
78+
79+
# prepare changes
80+
for h in organization_changes:
81+
prev = h.changes['current_organization'][0]
82+
next = h.changes['current_organization'][1]
83+
organization_change_log.append({
84+
'timestamp': h.timestamp,
85+
'prev': None if prev == 'None' else Organization.objects.filter(id=prev).first(),
86+
'next': None if next == 'None' else Organization.objects.filter(id=next).first(),
87+
})
88+
for h in room_changes:
89+
prev = h.changes['current_room'][0]
90+
next = h.changes['current_room'][1]
91+
room_change_log.append({
92+
'timestamp': h.timestamp,
93+
'prev': None if prev == 'None' else Room.objects.filter(id=prev).first(),
94+
'next': None if next == 'None' else Room.objects.filter(id=next).first(),
95+
})
96+
for h in user_changes:
97+
prev = h.changes['current_user'][0]
98+
next = h.changes['current_user'][1]
99+
user_change_log.append({
100+
'timestamp': h.timestamp,
101+
'prev': None if prev == 'None' else CustomUser.objects.filter(id=prev).first(),
102+
'next': None if next == 'None' else CustomUser.objects.filter(id=next).first(),
103+
})
104+
105+
context['organization_change_log'] = organization_change_log
106+
context['room_change_log'] = room_change_log
107+
context['user_change_log'] = user_change_log
108+
67109
# Serialize data to JSON format
68110
context['battery_times'] = json.dumps(battery_times, cls=DjangoJSONEncoder)
69111
context['battery_charges'] = json.dumps(battery_charges, cls=DjangoJSONEncoder)
@@ -101,7 +143,6 @@ def get_context_data(self, **kwargs):
101143
sensors = defaultdict(list)
102144
# add available sensors
103145
for measurement in Measurement.objects.filter(device=device, time_measured=device.last_update).all():
104-
print(measurement.sensor_model)
105146
for value in measurement.values.all():
106147
sensors[SensorModel.get_sensor_name(measurement.sensor_model)].append(Dimension.get_name(value.dimension))
107148

app/main/util.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ def get_or_create_station(station_info: dict):
3636
id = station_info['device']
3737
)
3838
if created:
39-
station.device_name = station_info['device']
4039
station.model = station_info['model']
4140
station.firmware = station_info['firmware']
4241
station.api_key = station_info['apikey']

0 commit comments

Comments
 (0)