Commits (47)
...@@ -23,3 +23,4 @@ obj/ ...@@ -23,3 +23,4 @@ obj/
*.config *.config
*.sln *.sln
docs/build docs/build
static/
...@@ -17,6 +17,9 @@ Upgrade of existing systems running the Python 2.7 version will ...@@ -17,6 +17,9 @@ Upgrade of existing systems running the Python 2.7 version will
require assistance from the developer, Alan Mitchell, alan@analysisnorth.com. require assistance from the developer, Alan Mitchell, alan@analysisnorth.com.
Please contact him before attempting an upgrade. Please contact him before attempting an upgrade.
This version requires Python 3.7 or higher. For an automated server install
script, see the [bmon-install project](https://github.com/alanmitchell/bmon-install).
For detailed information about this software: For detailed information about this software:
### Please see the [BMON Documentation](http://bmon-documentation.readthedocs.io/en/latest/index.html) ### Please see the [BMON Documentation](http://bmon-documentation.readthedocs.io/en/latest/index.html)
...@@ -46,8 +46,9 @@ USE_TZ = True ...@@ -46,8 +46,9 @@ USE_TZ = True
# Absolute path to the directory static files should be collected to. # Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files # Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS. # in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/var/www/example.com/static/" # Collect static files into the 'static' directory in the root of this
STATIC_ROOT = join(PROJ_PATH, '..', '..', settings.BMSAPP_STATIC_APP_NAME) # project.
STATIC_ROOT = join(PROJ_PATH, 'static/')
# URL prefix for static files. # URL prefix for static files.
# Example: "http://example.com/static/", "http://static.example.com/" # Example: "http://example.com/static/", "http://static.example.com/"
......
...@@ -13,18 +13,18 @@ import logging ...@@ -13,18 +13,18 @@ import logging
# need to include thise Store Key when they post the data. # need to include thise Store Key when they post the data.
# See bmsapp/views.storereading() and bmsapp/views.storereadings() for details # See bmsapp/views.storereading() and bmsapp/views.storereadings() for details
# of how the Store Key is included in a reading post. # of how the Store Key is included in a reading post.
BMSAPP_STORE_KEY = 'PutStorageKeyHere' BMSAPP_STORE_KEY = '{{ store_key.stdout }}'
# Store key used with old URL pattern. # Store key used with old URL pattern.
# *** NOT USED WITH NEW INSTALLS. LEAVE COMMENTED OUT *** # *** NOT USED WITH NEW INSTALLS. LEAVE COMMENTED OUT ***
# BMSAPP_STORE_KEY_OLD = '' # BMSAPP_STORE_KEY_OLD = ''
# Text only title of this application. Used as part of the HTML page title. # Text only title of this application. Used as part of the HTML page title.
BMSAPP_TITLE_TEXT = 'XYZ Remote Monitoring' BMSAPP_TITLE_TEXT = '{{ bmon_site_title }}'
# Header that appears at the top of every page. Can include HTML # Header that appears at the top of every page. Can include HTML
# and is placed inside a <div> tag with an CSS ID of 'header'. # and is placed inside a <div> tag with an CSS ID of 'header'.
BMSAPP_HEADER = 'XYZ Remote Monitoring' BMSAPP_HEADER = '{{ bmon_site_title }}'
# Information about the Navigation links that appear at the top of each web page. # Information about the Navigation links that appear at the top of each web page.
# First item in tuple is Text that will be shown for the link. # First item in tuple is Text that will be shown for the link.
...@@ -87,16 +87,18 @@ BMSAPP_ECOBEE_API_KEY = '32 Character API Key goes here' ...@@ -87,16 +87,18 @@ BMSAPP_ECOBEE_API_KEY = '32 Character API Key goes here'
# are settings required for the general Django software. # are settings required for the general Django software.
# Hosts/domain names that are valid for this site; required if DEBUG is False. # Hosts/domain names that are valid for this site; required if DEBUG is False.
# For a Webfaction site using the subdomain that Webfaction provides, the entry
# would be "bmon.<username>.webfactional.com", where <username> is your Webfaction
# username; this assumes you are using the 'bmon' subdomain for BMON.
# More documentation at: https://docs.djangoproject.com/en/1.7/ref/settings/#allowed-hosts # More documentation at: https://docs.djangoproject.com/en/1.7/ref/settings/#allowed-hosts
ALLOWED_HOSTS = ['bmon.<username>.webfactional.com'] ALLOWED_HOSTS = [
'{{ bmon_domain }}',
'www.{{ bmon_domain }}',
'{{ server_ip.stdout }}',
'localhost',
]
# This is the Django Secret Key, needed for security purposes. # This is the Django Secret Key, needed for security purposes.
# Make this unique, and don't share it with anybody. # Make this unique, and don't share it with anybody.
# See documentation at https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-SECRET_KEY # See documentation at https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-SECRET_KEY
SECRET_KEY = 'Put a Unique Unpredictable Secret Key Here' SECRET_KEY = '{{ django_secret_key.stdout }}'
# Local time zone for this installation. Choices can be found here: # Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
...@@ -116,28 +118,25 @@ LANGUAGE_CODE = 'en-us' ...@@ -116,28 +118,25 @@ LANGUAGE_CODE = 'en-us'
# NOTE: You can also view the error log for the BMON application by browsing to the page: # NOTE: You can also view the error log for the BMON application by browsing to the page:
# <application URL>/show-log # <application URL>/show-log
ADMINS = ( ADMINS = (
# ('Admin Name Here', 'Admin Email Address Here'), ('{{ admin_email_name }}', '{{ admin_email_address }}'),
) )
# The following email settings need to be filled out for sending out alerts from # The following email settings need to be filled out for sending out alerts from
# the BMON app. # the BMON app.
# For the Webfaction hosting service, see documentation at: # For an article on using Gmail settings: https://data-flair.training/blogs/django-send-email/
# http://docs.webfaction.com/software/django/getting-started.html#configuring-django-to-send-email-messages
# For general Django documentation on these settings, see: # For general Django documentation on these settings, see:
# https://docs.djangoproject.com/en/1.7/ref/settings/#std:setting-EMAIL_HOST # https://docs.djangoproject.com/en/2.2/ref/settings/#std:setting-EMAIL_HOST
# the SMTP server used to send mail, 'smtp.webfaction.com' or the Webfaction hosting service # the SMTP server used to send mail, 'smtp.webfaction.com' or the Webfaction hosting service
EMAIL_HOST = 'smtp.webfaction.com' EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'mailbox_username' EMAIL_HOST = '{{ email_smtp_host }}'
EMAIL_HOST_PASSWORD = 'mailbox_password' EMAIL_PORT = 587
# If you are using the Webfaction smtp server, the two FROM adddresses below need to EMAIL_HOST_USER = '{{ email_username }}'
# be email addresses set up in your Webfaction account (you can use the same address EMAIL_HOST_PASSWORD = '{{ email_password }}'
# for both, if desired). The Webfaction server will not send emails with a FROM address
# that is not on the Webfaction host.
# this will be the FROM for alert messages # this will be the FROM for alert messages
DEFAULT_FROM_EMAIL = 'valid_from_email_address' DEFAULT_FROM_EMAIL = '{{ email_username }}'
# this is the FROM for error messages # this is the FROM for error messages
SERVER_EMAIL = 'valid_from_email_for_error_messages' SERVER_EMAIL = '{{ email_username }}'
# If DEBUG=True, a detailed error traceback is displayed in the browser when an error # If DEBUG=True, a detailed error traceback is displayed in the browser when an error
# occurs. This setting should be False for production use for security reasons, but if # occurs. This setting should be False for production use for security reasons, but if
...@@ -145,11 +144,6 @@ SERVER_EMAIL = 'valid_from_email_for_error_messages' ...@@ -145,11 +144,6 @@ SERVER_EMAIL = 'valid_from_email_for_error_messages'
# debug information. # debug information.
DEBUG = False DEBUG = False
# This is the name you gave to the Static application created in the Webfaction Control
# Panel to serve static Django media. This is only used to create the STATIC_ROOT setting
# in the settings_common file.
BMSAPP_STATIC_APP_NAME = 'bmon_static'
# Import settings that are generally common to all installs of BMON. # Import settings that are generally common to all installs of BMON.
from .settings_common import * from .settings_common import *
......
#!/usr/bin/env python3
'''Adds buildings, sensors, and Dashboard items associated with a number of
LT22222-L boat sensors. The Dev EUI values are passed in one per line
in a text file, the path of which is the command line parameter of this script.
All SensorGroup and Unit objects must be present before running this script.
Building objects will be created.
Run the script with:
./add_boats.py sensor_euis.txt
'''
import os
import sys
import traceback
import django
import pandas as pd
# need to add the directory two above this to the Python path
# so the bmsapp package can be found
this_dir = os.path.dirname(os.path.abspath(__file__))
app_dir = os.path.abspath(os.path.join(this_dir, '../../'))
sys.path.insert(0, app_dir)
# prep the Django environment because we need access to the module
# that manipulates the Reading database.
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "bmon.settings")
django.setup()
from bmsapp.models import DashboardItem, SensorGroup, Unit, Sensor, Building, BldgToSensor
# get the needed Sensor Unit objects
unit_on_off = Unit.objects.filter(label='1=On 0=Off')[0]
unit_volts = Unit.objects.filter(label='Volts')[0]
unit_deg_f = Unit.objects.filter(label='deg F')[0]
unit_db = Unit.objects.filter(label='dB')[0]
# Sensors to create with info
SENSORS = (
('highWater', 'High Bilge Water', unit_on_off, ('LED', 1, 1, 0, 0, None, None)),
('shorePower', 'Shore Power', unit_on_off, ('LED', 1, 2, 1, 1, None, None)),
('bilgePump', 'Bilge Pump', unit_on_off, ('graph', 1, 3, 0, 1, 0, 1)),
('batteryV', 'Battery Voltage', unit_volts, ('gauge', 2, 1, 12.0, 14.7, None, None)),
('temperature', 'Interior Temperature', unit_deg_f, ('graph', 2, 2, 35, 85, 10, 80)),
('snr', 'Boat Sensor Signal', unit_db, ('graph', 2, 3, -7, 15, -15, 15)),
)
# Get needed Sensor Group objects
grp_boat_mon = SensorGroup.objects.filter(title='Boat Monitoring')[0]
grp_weather = SensorGroup.objects.filter(title='Weather')[0]
# Get the two Seward weather sensors
sensor_wx_temp = Sensor.objects.filter(sensor_id='PAWD_temp')[0]
sensor_wx_wind = Sensor.objects.filter(sensor_id='PAWD_wind')[0]
# Read the EUIs from the file and capitalize.
euis = [eui.strip().upper() for eui in open(sys.argv[1]).readlines() if len(eui.strip())]
for eui in euis:
try:
# make a building
bldg_title = f'Boat {eui[-4:]}'
bldg = Building(
title=bldg_title,
latitude=60.118170,
longitude=-149.436431,
)
bldg.save()
# make the sensors for this boat
sort_order = 10
for s_suffix, s_title, s_unit, s_dash in SENSORS:
sensor = Sensor(sensor_id=f'{eui}_{s_suffix}', title=s_title, unit=s_unit)
sensor.save()
# now the object that links the sensor to a building
link = BldgToSensor(building=bldg, sensor=sensor, sensor_group=grp_boat_mon, sort_order=sort_order)
link.save()
sort_order += 10
# Add a dashboard item
d_type, d_row, d_col, d_min_norm, d_max_norm, d_min_ax, d_max_ax = s_dash
if len(d_type):
DashboardItem(
building=bldg,
widget_type=d_type,
row_number=d_row,
column_number=d_col,
sensor=link,
minimum_normal_value=d_min_norm,
maximum_normal_value=d_max_norm,
minimum_axis_value=d_min_ax,
maximum_axis_value=d_max_ax,
).save()
# Add the two Seward Weather items
link = BldgToSensor(building=bldg, sensor=sensor_wx_temp, sensor_group=grp_weather, sort_order=10)
link.save()
DashboardItem(
building=bldg,
widget_type='graph',
row_number=3,
column_number=1,
sensor=link,
minimum_normal_value=20,
maximum_normal_value=60,
).save()
link = BldgToSensor(building=bldg, sensor=sensor_wx_wind, sensor_group=grp_weather, sort_order=20)
link.save()
DashboardItem(
building=bldg,
widget_type='graph',
row_number=3,
column_number=2,
sensor=link,
minimum_normal_value=0,
maximum_normal_value=25,
).save()
except:
print(f'Error processing: {eui}')
traceback.print_exc()
...@@ -139,7 +139,7 @@ ...@@ -139,7 +139,7 @@
</div> </div>
<div class="col"> <div class="col">
<p>Thanks to the Alaska Housing Finance Corporation for funding development of most <p>Thanks to the Alaska Housing Finance Corporation for funding development of most
of this application.</p> of the BMON Open Source Software used to build this site.</p>
</div> </div>
{% if logout_show %} {% if logout_show %}
<div class="col-auto"> <div class="col-auto">
......
#!/usr/local/bin/python3.7 #!/usr/bin/env python3
import os import os
import sys import sys
......
# Base requirements for deployment of BMON. certifi==2020.12.5
# To use: pip install -r requirements.txt chardet==4.0.0
django-extensions==3.1.1
# NOTE: The pip Python package must be installed to use this django-lockdown==4.0.0
# requirements.txt file. django==2.2.19
et-xmlfile==1.0.1
Django==2.2.4 gunicorn==20.0.4
django-extensions==2.1.6 idna==2.10
numpy==1.16.2 markdown==3.3.4
numexpr==2.6.9 metar==1.8.0
pandas==0.24.2 modbus-tk==1.1.2
python-dateutil===2.8.0 numexpr==2.7.3
pytz>=2018.9 numpy==1.20.1
requests==2.21.0 openpyxl==3.0.7
xlwt==1.3.0 pandas==1.2.3
PyYAML==5.1 ply==3.11
Markdown==3.0.1 pyasn1==0.4.8
pycryptodomex==3.10.1
pyserial==3.5
pysmi==0.3.4
pysnmp==4.4.12
python-dateutil==2.8.1
pytz==2021.1
pyyaml==5.4.1
requests==2.25.1
selenium==3.141.0 selenium==3.141.0
pysnmp==4.4.9 six==1.15.0
modbus-tk==0.5.11 sqlparse==0.4.1
xlrd==1.2.0 urllib3==1.26.4
metar==1.7.0 xlrd==2.0.1
lxml==4.3.2 xlwt==1.3.0
django-lockdown==3.0.0
#!/bin/sh #!/bin/bash
# Script to update BMON to the most recent version, # Script to update BMON to the most recent version,
# applying migrations and copying static files to # applying migrations and copying static files to
# the static serving application. # the static serving application.
../apache2/bin/stop
git pull git pull
./manage.py migrate env/bin/python manage.py migrate
./manage.py collectstatic --noinput env/bin/python manage.py collectstatic --noinput
../apache2/bin/restart sudo systemctl restart bmon