First stab at power utilization tracking

This commit is contained in:
Jeremy Stretch 2019-04-10 16:32:13 -04:00
parent 3d5f85c0ca
commit ac3e899f5e
2 changed files with 86 additions and 1 deletions

View File

@ -9,7 +9,7 @@ from django.contrib.postgres.fields import ArrayField, JSONField
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.db.models import Count, Q from django.db.models import Count, Q, Sum
from django.urls import reverse from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager from taggit.managers import TaggableManager
@ -1938,6 +1938,41 @@ class PowerPort(CableTermination, ComponentModel):
"Connected endpoint must be a PowerOutlet or PowerFeed, not {}.".format(type(value)) "Connected endpoint must be a PowerOutlet or PowerFeed, not {}.".format(type(value))
) )
def get_power_stats(self):
"""
Return power utilization statistics
"""
feed = self._connected_powerfeed
if not feed or not self.poweroutlets.count():
return None
stats = []
powerfeed_available = self._connected_powerfeed.available_power
outlet_ids = PowerOutlet.objects.filter(power_port=self).values_list('pk', flat=True)
utilization = PowerPort.objects.filter(_connected_poweroutlet_id__in=outlet_ids).aggregate(
maximum_draw=Sum('maximum_draw'),
allocated_draw=Sum('allocated_draw'),
)
utilization['outlets'] = len(outlet_ids)
utilization['available_power'] = powerfeed_available
stats.append(utilization)
# Per-leg stats for three-phase feeds
if feed.phase == POWERFEED_PHASE_3PHASE:
for leg, leg_name in POWERFEED_LEG_CHOICES:
outlet_ids = PowerOutlet.objects.filter(power_port=self, feed_leg=leg).values_list('pk', flat=True)
utilization = PowerPort.objects.filter(_connected_poweroutlet_id__in=outlet_ids).aggregate(
maximum_draw=Sum('maximum_draw'),
allocated_draw=Sum('allocated_draw'),
)
utilization['name'] = 'Leg {}'.format(leg_name)
utilization['outlets'] = len(outlet_ids)
utilization['available_power'] = powerfeed_available / 3
stats.append(utilization)
return stats
# #
# Power outlets # Power outlets
@ -2923,3 +2958,10 @@ class PowerFeed(ChangeLoggedModel, CableTermination, CustomFieldModel):
def get_status_class(self): def get_status_class(self):
return STATUS_CLASSES[self.status] return STATUS_CLASSES[self.status]
@property
def available_power(self):
kva = self.voltage * self.amperage * self.max_utilization
if self.phase == POWERFEED_PHASE_3PHASE:
return kva * 1.732
return kva

View File

@ -332,6 +332,49 @@
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
{% if power_ports and poweroutlets %}
<div class="panel panel-default">
<div class="panel-heading">
<strong>Power Utilization</strong>
</div>
<table class="table table-hover panel-body">
<tr>
<th>Input</th>
<th>Outlets</th>
<th>Allocated/Max (W)</th>
<th>Available (VA)</th>
</tr>
{% for pp in power_ports %}
{% for leg in pp.get_power_stats %}
<tr>
{% if leg.name %}
<td style="padding-left: 20px">{{ leg.name }}</td>
{% else %}
<td>{{ pp }}</td>
{% endif %}
<td>{{ leg.outlets|placeholder }}</td>
<td>{{ leg.allocated_draw }} / {{ leg.maximum_draw }}</td>
<td>{{ leg.available_power }}</td>
</tr>
{% endfor %}
{% endfor %}
</table>
{% if perms.dcim.add_interface or perms.dcim.add_consoleport or perms.dcim.add_powerport %}
<div class="panel-footer text-right noprint">
{% if perms.dcim.add_consoleport %}
<a href="{% url 'dcim:consoleport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add console port
</a>
{% endif %}
{% if perms.dcim.add_powerport %}
<a href="{% url 'dcim:powerport_add' pk=device.pk %}" class="btn btn-xs btn-primary">
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span> Add power port
</a>
{% endif %}
</div>
{% endif %}
</div>
{% endif %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">