Skip to content

Commit

Permalink
Statuspagina: onderdelen 'backup' en 'mindergas upload' toevoegen #292
Browse files Browse the repository at this point in the history
  • Loading branch information
dennissiemensma committed Jul 23, 2018
1 parent 9ad9b4b commit 597f05a
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 85 deletions.
153 changes: 112 additions & 41 deletions dsmr_backend/services.py
Expand Up @@ -12,6 +12,9 @@
from dsmr_weather.models.settings import WeatherSettings
from dsmr_datalogger.models.reading import DsmrReading
from dsmr_stats.models.statistics import DayStatistics
from dsmr_backup.models.settings import BackupSettings, DropboxSettings
from dsmr_mindergas.models.settings import MinderGasSettings
from dsmr_pvoutput.models.settings import PVOutputAddStatusSettings


def get_capabilities(capability=None):
Expand Down Expand Up @@ -75,78 +78,146 @@ def is_timestamp_passed(timestamp):
return timezone.now() >= timestamp


def status_info():
""" Returns the status info of the application. """
capabilities = get_capabilities()
def get_electricity_status(capabilities):
status = {
'capabilities': capabilities,
'electricity': {
'latest': None,
'minutes_since': None,
},
'gas': {
'latest': None,
'hours_since': None,
},
'readings': {
'latest': None,
'latest': None,
'minutes_since': None,
}

if capabilities['electricity']:
status['latest'] = ElectricityConsumption.objects.all().order_by('-pk')[0].read_at
diff = timezone.now() - status['latest']
status['minutes_since'] = round(diff.total_seconds() / 60)

return status


def get_gas_status(capabilities):
status = {
'latest': None,
'hours_since': None,
}

if capabilities['gas']:
status['latest'] = GasConsumption.objects.all().order_by('-pk')[0].read_at
diff = timezone.now() - status['latest']
status['hours_since'] = round(diff.total_seconds() / 3600)

return status


def get_reading_status():
status = {
'latest': None,
'seconds_since': None,
'unprocessed': {
'count': None,
'seconds_since': None,
'unprocessed': {
'count': None,
'seconds_since': None,
},
},
'statistics': {
'latest': None,
'days_since': None,
},
}

status['readings']['unprocessed']['count'] = DsmrReading.objects.unprocessed().count()
status['unprocessed']['count'] = DsmrReading.objects.unprocessed().count()

try:
first_unprocessed_reading = DsmrReading.objects.unprocessed().order_by('timestamp')[0]
except IndexError:
pass
else:
diff = timezone.now() - first_unprocessed_reading.timestamp
status['readings']['unprocessed']['seconds_since'] = round(diff.total_seconds())
status['unprocessed']['seconds_since'] = round(diff.total_seconds())

try:
status['readings']['latest'] = DsmrReading.objects.all().order_by('-pk')[0].timestamp
status['latest'] = DsmrReading.objects.all().order_by('-pk')[0].timestamp
except IndexError:
pass
else:
# It seems that smart meters sometimes have their clock set into the future, so we correct it.
if status['readings']['latest'] > timezone.now():
status['readings']['seconds_since'] = 0
status['readings']['latest'] = timezone.now()
if status['latest'] > timezone.now():
status['seconds_since'] = 0
status['latest'] = timezone.now()
else:
diff = timezone.now() - status['readings']['latest']
status['readings']['seconds_since'] = round(diff.total_seconds())
diff = timezone.now() - status['latest']
status['seconds_since'] = round(diff.total_seconds())

if capabilities['electricity']:
status['electricity']['latest'] = ElectricityConsumption.objects.all().order_by('-pk')[0].read_at
diff = timezone.now() - status['electricity']['latest']
status['electricity']['minutes_since'] = round(diff.total_seconds() / 60)
return status

if capabilities['gas']:
status['gas']['latest'] = GasConsumption.objects.all().order_by('-pk')[0].read_at
diff = timezone.now() - status['gas']['latest']
status['gas']['hours_since'] = round(diff.total_seconds() / 3600)

def get_statistics_status():
status = {
'latest': None,
'days_since': None,
}

try:
status['statistics']['latest'] = DayStatistics.objects.all().order_by('-day')[0].day
status['latest'] = DayStatistics.objects.all().order_by('-day')[0].day
except IndexError:
pass
else:
status['statistics']['days_since'] = (
timezone.now().date() - status['statistics']['latest']
status['days_since'] = (
timezone.now().date() - status['latest']
).days

return status


def status_info():
""" Returns the status info of the application. """
capabilities = get_capabilities()
status = {
'capabilities': capabilities,
'electricity': get_electricity_status(capabilities),
'gas': get_gas_status(capabilities),
'readings': get_reading_status(),
'statistics': get_statistics_status(),
'tools':
{
'backup': {
'enabled': False,
'latest_backup': None,
},
'dropbox': {
'enabled': False,
'latest_sync': None,
},
'pvoutput': {
'enabled': False,
'latest_sync': None,
},
'mindergas': {
'enabled': False,
'latest_sync': None,
},
}
}

# (External) tools below.
backup_settings = BackupSettings.get_solo()

if backup_settings.daily_backup and backup_settings.latest_backup:
status['tools']['backup']['enabled'] = True
status['tools']['backup']['latest_backup'] = backup_settings.latest_backup

dropbox_settings = DropboxSettings.get_solo()

if dropbox_settings.access_token and dropbox_settings.latest_sync:
status['tools']['dropbox']['enabled'] = True
status['tools']['dropbox']['latest_sync'] = dropbox_settings.latest_sync

pvoutput_settings = PVOutputAddStatusSettings.get_solo()

if pvoutput_settings.export and pvoutput_settings.latest_sync:
status['tools']['pvoutput']['enabled'] = True
status['tools']['pvoutput']['latest_sync'] = pvoutput_settings.latest_sync

mindergas_settings = MinderGasSettings.get_solo()

if mindergas_settings.export and mindergas_settings.latest_sync:
status['tools']['mindergas']['enabled'] = True
status['tools']['mindergas']['latest_sync'] = mindergas_settings.latest_sync

return status


def is_recent_installation():
""" Checks whether this is a new installation, by checking the interval to the first migration. """
has_old_migration = MigrationRecorder.Migration.objects.filter(
Expand Down
38 changes: 38 additions & 0 deletions dsmr_backend/tests/test_services.py
Expand Up @@ -8,6 +8,9 @@
from dsmr_consumption.models.consumption import ElectricityConsumption, GasConsumption
from dsmr_weather.models.reading import TemperatureReading
from dsmr_weather.models.settings import WeatherSettings
from dsmr_backup.models.settings import BackupSettings, DropboxSettings
from dsmr_mindergas.models.settings import MinderGasSettings
from dsmr_pvoutput.models.settings import PVOutputAddStatusSettings
import dsmr_backend.services


Expand Down Expand Up @@ -188,6 +191,7 @@ def test_disabled_capabilities(self):
@mock.patch('django.core.cache.cache.set')
@mock.patch('django.core.cache.cache.get')
def test_capability_caching(self, get_cache_mock, set_cache_mock):
""" Whether capabilities are cached. """
get_cache_mock.return_value = None

self.assertFalse(get_cache_mock.called)
Expand All @@ -208,6 +212,40 @@ def test_capability_caching(self, get_cache_mock, set_cache_mock):
self.assertFalse(set_cache_mock.called)
self.assertEqual(first_capabilities, second_capabilities)

@mock.patch('django.utils.timezone.now')
def test_status_info(self, now_mock):
""" Application status info dict. """
now_mock.return_value = timezone.make_aware(timezone.datetime(2018, 1, 1))

tools_status = dsmr_backend.services.status_info()['tools']

# Tools should be asserted, other content is tested in dsmr_frontend.
self.assertFalse(tools_status['backup']['enabled'])
self.assertFalse(tools_status['dropbox']['enabled'])
self.assertFalse(tools_status['pvoutput']['enabled'])
self.assertFalse(tools_status['mindergas']['enabled'])
self.assertIsNone(tools_status['backup']['latest_backup'])
self.assertIsNone(tools_status['dropbox']['latest_sync'])
self.assertIsNone(tools_status['pvoutput']['latest_sync'])
self.assertIsNone(tools_status['mindergas']['latest_sync'])

# Now when enabled.
BackupSettings.objects.update(daily_backup=True, latest_backup=timezone.now())
DropboxSettings.objects.update(access_token='xxx', latest_sync=timezone.now())
MinderGasSettings.objects.update(export=True, latest_sync=timezone.now())
PVOutputAddStatusSettings.objects.update(export=True, latest_sync=timezone.now())

tools_status = dsmr_backend.services.status_info()['tools']

self.assertTrue(tools_status['backup']['enabled'])
self.assertTrue(tools_status['dropbox']['enabled'])
self.assertTrue(tools_status['pvoutput']['enabled'])
self.assertTrue(tools_status['mindergas']['enabled'])
self.assertEqual(tools_status['backup']['latest_backup'], timezone.now())
self.assertEqual(tools_status['dropbox']['latest_sync'], timezone.now())
self.assertEqual(tools_status['pvoutput']['latest_sync'], timezone.now())
self.assertEqual(tools_status['mindergas']['latest_sync'], timezone.now())


@mock.patch('requests.get')
class TestIslatestVersion(TestCase):
Expand Down
18 changes: 18 additions & 0 deletions dsmr_mindergas/migrations/0004_mindergas_latest_sync.py
@@ -0,0 +1,18 @@
# Generated by Django 2.0.7 on 2018-07-23 17:26

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dsmr_mindergas', '0003_mindergas_next_export_datetime'),
]

operations = [
migrations.AddField(
model_name='mindergassettings',
name='latest_sync',
field=models.DateTimeField(blank=True, default=None, help_text='Timestamp of latest sync with MinderGas. Automatically updated by application.', null=True, verbose_name='Latest sync'),
),
]
7 changes: 7 additions & 0 deletions dsmr_mindergas/models/settings.py
Expand Up @@ -25,6 +25,13 @@ class MinderGasSettings(SingletonModel):
'More information can be found here: https://www.mindergas.nl/member/api'
)
)
latest_sync = models.DateTimeField(
default=None,
null=True,
blank=True,
verbose_name=_('Latest sync'),
help_text=_('Timestamp of latest sync with MinderGas. Automatically updated by application.')
)
next_export = models.DateTimeField(
default=None,
null=True,
Expand Down
6 changes: 4 additions & 2 deletions dsmr_mindergas/services.py
Expand Up @@ -42,6 +42,7 @@ def export():

# Push back for a day and a bit.
next_export = midnight + timezone.timedelta(hours=24, minutes=random.randint(15, 59))
mindergas_settings = MinderGasSettings.get_solo()

try:
last_gas_reading = GasConsumption.objects.filter(
Expand All @@ -53,7 +54,6 @@ def export():
last_gas_reading = None
print(' - MinderGas | No gas readings found for uploading')
else:
mindergas_settings = MinderGasSettings.get_solo()
print(' - MinderGas | Uploading gas meter position: {}'.format(last_gas_reading.delivered))

# Register telegram by simply sending it to the application with a POST request.
Expand All @@ -70,8 +70,10 @@ def export():
# Try again in an hour.
next_export = timezone.now() + timezone.timedelta(hours=1)
print(' [!] MinderGas upload failed (HTTP {}): {}'.format(response.status_code, response.text))
else:
# Keep track.
mindergas_settings.latest_sync = timezone.now()

print(' - MinderGas | Delaying the next upload until: {}'.format(next_export))
mindergas_settings = MinderGasSettings.get_solo()
mindergas_settings.next_export = next_export
mindergas_settings.save()

0 comments on commit 597f05a

Please sign in to comment.