Source code for habitat.sensors.stdtelem

# Copyright 2011 (C) Adam Greig, Daniel Richman
#
# This file is part of habitat.
#
# habitat is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# habitat is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with habitat.  If not, see <http://www.gnu.org/licenses/>.

"""
Sensor functions for dealing with telemetry.
"""

import math
import datetime
from time import strptime

__all__ = ["time", "coordinate", "binary_timestamp", "binary_bcd_time"]


[docs]def time(data): """ Parse the time, validating it and returning the standard ``HH:MM:SS``. Accepted formats include ``HH:MM:SS``, ``HHMMSS``, ``HH:MM`` and ``HHMM``. It uses strptime to ensure the values are sane. """ if len(data) == 8: t = strptime(data, "%H:%M:%S") elif len(data) == 6: t = strptime(data, "%H%M%S") elif len(data) == 5: t = strptime(data, "%H:%M") elif len(data) == 4: t = strptime(data, "%H%M") else: raise ValueError("Invalid time value.") return "{0.tm_hour:02d}:{0.tm_min:02d}:{0.tm_sec:02d}".format(t)
[docs]def coordinate(config, data): """ Parses ASCII latitude or longitude into a decimal-degrees float. Either decimal degrees or degrees with decimal minutes are accepted (degrees, minutes and seconds are not currently supported). The format is specified in ``config["format"]`` and can look like either ``dd.dddd`` or ``ddmm.mmmm``, with one to three leading ``d`` characters and one to six trailing ``d`` or ``m`` characters. """ if "format" not in config: raise ValueError("Coordinate format missing") coordinate_format = config["format"] left, right = coordinate_format.split(".") if left[-1] == "d" and right[-1] == "d": coord = float(data) elif left[0] == "d" and left[-1] == "m" and right[-1] == "m": val = float(data) degrees = int(val / 100) minutes = val - (degrees * 100) if minutes > 60.0: raise ValueError("Minutes component > 60.") coord = degrees + (minutes / 60) exponent = 3 + ( len(data.split('.')[1]) if data.find('.') > -1 else 0 ) coord = round(coord, exponent) else: raise ValueError("Invalid coordinate format") if 'name' in config and config['name'] == 'latitude': if not (-90.0 <= coord <= 90.0): raise ValueError("Coordinate out of range (-90 <= x <= 90)") else: if not (-180.0 <= coord <= 180.0): raise ValueError("Coordinate out of range (-180 <= x <= 180)") return coord
[docs]def binary_timestamp(data): """ Parse a four byte unsigned integer into a time string in the format "HH:MM:SS". Date information is thus discarded. """ d = datetime.datetime.utcfromtimestamp(data) return d.strftime("%H:%M:%S")
[docs]def binary_bcd_time(data): """ Parse two or three bytes (given as a string, format ``2s`` or ``3s``) into hours, minutes and optionally seconds in the format "HH:MM:SS". """ if len(data) == 2: if ord(data[0]) > 23 or ord(data[1]) > 59: raise ValueError("Data out of range (hours 0-23, mins 0-59)") return "{0:02d}:{1:02d}:00".format(*[ord(c) for c in data]) if len(data) == 3: if ord(data[0]) > 23 or ord(data[1]) > 59 or ord(data[2]) > 59: raise ValueError("Data out of range (hours 0-23; mins, secs 0-59)") return "{0:02d}:{1:02d}:{2:02d}".format(*[ord(c) for c in data]) else: raise ValueError("Data not correct length (2 or 3 bytes)")