Skip to content

Commit

Permalink
Add Functions to API, add missing Input Channels to Input API calls
Browse files Browse the repository at this point in the history
  • Loading branch information
kizniche committed Mar 8, 2021
1 parent 7eae813 commit e22da36
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 11 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ The new weather input acquires current and future weather conditions from openwe
- Add user_scripts directory for user code that's preserved during upgrade/export/import ([#930](https://github.com/kizniche/mycodo/issues/930))
- Add pin mode option (float, pull-up, pull-down) for Edge and State Inputs
- Add Method: Cascaded Method, allows combining (multiply) any number of existing methods ([discussion](https://kylegabriel.com/forum/general-discussion/refactor-method-implementation-to-enable-further-methods/))
- Add Functions and to API
- Add missing Input Channels to Input API calls

### Miscellaneous

Expand Down
5 changes: 5 additions & 0 deletions mycodo/databases/models/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ def __repr__(self):
return "<{cls}(id={s.id})>".format(s=self, cls=self.__class__.__name__)


class FunctionSchema(ModelSchema):
class Meta:
model = CustomController


class FunctionChannel(CRUDMixin, db.Model):
__tablename__ = "function_channel"
__table_args__ = {'extend_existing': True}
Expand Down
2 changes: 2 additions & 0 deletions mycodo/mycodo_flask/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
if 'application/json' in api.representations:
del api.representations['application/json']


# Add API v1 + json accept content type
@api.representation('application/vnd.mycodo.v1+json')
def api_v1(data, code, headers):
Expand All @@ -61,6 +62,7 @@ def init_api(app):
import mycodo.mycodo_flask.api.choices
import mycodo.mycodo_flask.api.controller
import mycodo.mycodo_flask.api.daemon
import mycodo.mycodo_flask.api.function
import mycodo.mycodo_flask.api.input
import mycodo.mycodo_flask.api.math
import mycodo.mycodo_flask.api.measurement
Expand Down
103 changes: 103 additions & 0 deletions mycodo/mycodo_flask/api/function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# coding=utf-8
import logging
import traceback

import flask_login
from flask_accept import accept
from flask_restx import Resource
from flask_restx import abort
from flask_restx import fields

from mycodo.databases.models import CustomController
from mycodo.databases.models import DeviceMeasurements
from mycodo.databases.models import FunctionChannel
from mycodo.databases.models.controller import FunctionChannelSchema
from mycodo.databases.models.controller import FunctionSchema
from mycodo.databases.models.measurement import DeviceMeasurementsSchema
from mycodo.mycodo_flask.api import api
from mycodo.mycodo_flask.api import default_responses
from mycodo.mycodo_flask.api.sql_schema_fields import device_measurement_fields
from mycodo.mycodo_flask.api.sql_schema_fields import function_channel_fields
from mycodo.mycodo_flask.api.sql_schema_fields import function_fields
from mycodo.mycodo_flask.api.utils import get_from_db
from mycodo.mycodo_flask.api.utils import return_list_of_dictionaries
from mycodo.mycodo_flask.utils import utils_general

logger = logging.getLogger(__name__)

ns_function = api.namespace('functions', description='Function operations')

function_single_fields = api.model('Function Status Fields', {
'function settings': fields.Nested(function_fields),
'function channels': fields.List(fields.Nested(function_channel_fields)),
'device measurements': fields.List(fields.Nested(device_measurement_fields)),
})

function_list_fields = api.model('Function Fields List', {
'function settings': fields.List(fields.Nested(function_fields)),
'function channels': fields.List(fields.Nested(function_channel_fields))
})


@ns_function.route('/')
@ns_function.doc(security='apikey', responses=default_responses)
class Functions(Resource):
"""Function information"""

@accept('application/vnd.mycodo.v1+json')
@ns_function.marshal_with(function_list_fields)
@flask_login.login_required
def get(self):
"""Show all function settings"""
if not utils_general.user_has_permission('view_settings'):
abort(403)
try:
list_data = get_from_db(FunctionSchema, CustomController)
list_channels = get_from_db(FunctionChannelSchema, FunctionChannel)
if list_data:
return {'function settings': list_data,
'function channels': list_channels}, 200
except Exception:
abort(500,
message='An exception occurred',
error=traceback.format_exc())


@ns_function.route('/<string:unique_id>')
@ns_function.doc(
security='apikey',
responses=default_responses,
params={'unique_id': 'The unique ID of the function'}
)
class SettingsFunctionsUniqueID(Resource):
"""Interacts with function settings in the SQL database"""

@accept('application/vnd.mycodo.v1+json')
@ns_function.marshal_with(function_single_fields)
@flask_login.login_required
def get(self, unique_id):
"""Show the settings for an function"""
if not utils_general.user_has_permission('view_settings'):
abort(403)
try:
list_data = get_from_db(FunctionSchema, CustomController, unique_id=unique_id)

function_channel_schema = FunctionChannelSchema()
list_channels = return_list_of_dictionaries(
function_channel_schema.dump(
FunctionChannel.query.filter_by(
function_id=unique_id).all(), many=True))

measure_schema = DeviceMeasurementsSchema()
list_measurements = return_list_of_dictionaries(
measure_schema.dump(
DeviceMeasurements.query.filter_by(
device_id=unique_id).all(), many=True))

return {'function settings': list_data,
'function channels': list_channels,
'device measurements': list_measurements}, 200
except Exception:
abort(500,
message='An exception occurred',
error=traceback.format_exc())
24 changes: 19 additions & 5 deletions mycodo/mycodo_flask/api/input.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,15 @@

from mycodo.databases.models import DeviceMeasurements
from mycodo.databases.models import Input
from mycodo.databases.models import InputChannel
from mycodo.databases.models.input import InputChannelSchema
from mycodo.databases.models.input import InputSchema
from mycodo.databases.models.measurement import DeviceMeasurementsSchema
from mycodo.mycodo_client import DaemonControl
from mycodo.mycodo_flask.api import api
from mycodo.mycodo_flask.api import default_responses
from mycodo.mycodo_flask.api.sql_schema_fields import device_measurement_fields
from mycodo.mycodo_flask.api.sql_schema_fields import input_channel_fields
from mycodo.mycodo_flask.api.sql_schema_fields import input_fields
from mycodo.mycodo_flask.api.utils import get_from_db
from mycodo.mycodo_flask.api.utils import return_list_of_dictionaries
Expand All @@ -27,12 +30,14 @@

input_single_fields = api.model('Input Status Fields', {
'input settings': fields.Nested(input_fields),
'input channels': fields.List(fields.Nested(input_channel_fields)),
'device measurements': fields.List(
fields.Nested(device_measurement_fields)),
})

input_list_fields = api.model('Input Fields List', {
'input settings': fields.List(fields.Nested(input_fields)),
'input channels': fields.List(fields.Nested(input_channel_fields))
})


Expand All @@ -50,8 +55,10 @@ def get(self):
abort(403)
try:
list_data = get_from_db(InputSchema, Input)
list_channels = get_from_db(InputChannelSchema, InputChannel)
if list_data:
return {'input settings': list_data}, 200
return {'input settings': list_data,
'input channels': list_channels}, 200
except Exception:
abort(500,
message='An exception occurred',
Expand All @@ -75,16 +82,23 @@ def get(self, unique_id):
if not utils_general.user_has_permission('view_settings'):
abort(403)
try:
dict_data = get_from_db(InputSchema, Input, unique_id=unique_id)
list_data = get_from_db(InputSchema, Input, unique_id=unique_id)

measure_schema = InputChannelSchema()
list_channels = return_list_of_dictionaries(
measure_schema.dump(
InputChannel.query.filter_by(
input_id=unique_id).all(), many=True))

measure_schema = DeviceMeasurementsSchema()
list_data = return_list_of_dictionaries(
list_measurements = return_list_of_dictionaries(
measure_schema.dump(
DeviceMeasurements.query.filter_by(
device_id=unique_id).all(), many=True))

return {'input settings': dict_data,
'device measurements': list_data}, 200
return {'input settings': list_data,
'input channels': list_channels,
'device measurements': list_measurements}, 200
except Exception:
abort(500,
message='An exception occurred',
Expand Down
12 changes: 6 additions & 6 deletions mycodo/mycodo_flask/api/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
ns_output = api.namespace('outputs', description='Output operations')

MODEL_STATES_STATE = ns_output.model('states', {
'*': fields.Wildcard(fields.String(description='on, off, or a duty cycle'),)
'*': fields.Wildcard(fields.String(description='on, off, or a duty cycle'),)
})
MODEL_STATES_CHAN = ns_output.model('channels', {
'*': fields.Wildcard(fields.Nested(
'*': fields.Wildcard(fields.Nested(
MODEL_STATES_STATE,
description='Dictionary with channel as key and state data as value.'))
})
Expand Down Expand Up @@ -140,10 +140,10 @@ def get(self, unique_id):
abort(403)

try:
dict_data = get_from_db(OutputSchema, Output, unique_id=unique_id)
list_data = get_from_db(OutputSchema, Output, unique_id=unique_id)

output_channel_schema = OutputChannelSchema()
list_data = return_list_of_dictionaries(
list_channels = return_list_of_dictionaries(
output_channel_schema.dump(
OutputChannel.query.filter_by(
output_id=unique_id).all(), many=True))
Expand All @@ -155,8 +155,8 @@ def get(self, unique_id):
for each_channel in states[unique_id]:
new_state_dict[str(each_channel)] = states[unique_id][each_channel]

return {'output device': dict_data,
'output device channels': list_data,
return {'output device': list_data,
'output device channels': list_channels,
'output device channel states': new_state_dict}, 200
except Exception:
abort(500,
Expand Down
28 changes: 28 additions & 0 deletions mycodo/mycodo_flask/api/sql_schema_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,25 @@

from mycodo.mycodo_flask.api import api

function_fields = api.model('Function Device Fields', {
'id': fields.Integer,
'unique_id': fields.String,
'name': fields.String,
'device': fields.String,
'is_activated': fields.Boolean,
'log_level_debug': fields.Boolean,
'custom_options': fields.String
})

function_channel_fields = api.model('Function Channel Fields', {
'id': fields.Integer,
'unique_id': fields.String,
'function_id': fields.String,
'channel': fields.Integer,
'name': fields.String,
'custom_options': fields.String,
})

device_measurement_fields = api.model('Device Measurement Settings Fields', {
'id': fields.Integer,
'unique_id': fields.String,
Expand Down Expand Up @@ -76,6 +95,15 @@
'custom_options': fields.String
})

input_channel_fields = api.model('Function Channel Fields', {
'id': fields.Integer,
'unique_id': fields.String,
'input_id': fields.String,
'channel': fields.Integer,
'name': fields.String,
'custom_options': fields.String,
})

math_fields = api.model('Math Settings Fields', {
'id': fields.Integer,
'unique_id': fields.String,
Expand Down

0 comments on commit e22da36

Please sign in to comment.