vitalsd: First functional commit

This gives us the beginnings of a vitalsd service that can dump output to the
serial ports.

Change-Id: I17c796984e39971fc7a6a1d1e1e1322b8094370a
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..372c13e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+__pycache__/
+
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..8bca305
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,93 @@
+# Code of Conduct
+
+## Our Pledge
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our project and
+our community a harassment-free experience for everyone, regardless of age, body
+size, disability, ethnicity, gender identity and expression, level of
+experience, education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+*   Using welcoming and inclusive language
+*   Being respectful of differing viewpoints and experiences
+*   Gracefully accepting constructive criticism
+*   Focusing on what is best for the community
+*   Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+*   The use of sexualized language or imagery and unwelcome sexual attention or
+    advances
+*   Trolling, insulting/derogatory comments, and personal or political attacks
+*   Public or private harassment
+*   Publishing others' private information, such as a physical or electronic
+    address, without explicit permission
+*   Other conduct which could reasonably be considered inappropriate in a
+    professional setting
+
+## Our Responsibilities
+
+Project maintainers are responsible for clarifying the standards of acceptable
+behavior and are expected to take appropriate and fair corrective action in
+response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, or to ban temporarily or permanently any
+contributor for other behaviors that they deem inappropriate, threatening,
+offensive, or harmful.
+
+## Scope
+
+This Code of Conduct applies both within project spaces and in public spaces
+when an individual is representing the project or its community. Examples of
+representing a project or community include using an official project e-mail
+address, posting via an official social media account, or acting as an appointed
+representative at an online or offline event. Representation of a project may be
+further defined and clarified by project maintainers.
+
+This Code of Conduct also applies outside the project spaces when the Project
+Steward has a reasonable belief that an individual's behavior may have a
+negative impact on the project or its community.
+
+## Conflict Resolution
+
+We do not believe that all conflict is bad; healthy debate and disagreement
+often yield positive results. However, it is never okay to be disrespectful or
+to engage in behavior that violates the project’s code of conduct.
+
+If you see someone violating the code of conduct, you are encouraged to address
+the behavior directly with those involved. Many issues can be resolved quickly
+and easily, and this gives people more control over the outcome of their
+dispute. If you are unable to resolve the matter for any reason, or if the
+behavior is threatening or harassing, report it. We are dedicated to providing
+an environment where participants feel welcome and safe.
+
+Reports should be directed to *[PROJECT STEWARD NAME(s) AND EMAIL(s)]*, the
+Project Steward(s) for *[PROJECT NAME]*. It is the Project Steward’s duty to
+receive and address reported violations of the code of conduct. They will then
+work with a committee consisting of representatives from the Open Source
+Programs Office and the Google Open Source Strategy team. If for any reason you
+are uncomfortable reaching out the Project Steward, please email
+opensource@google.com.
+
+We will investigate every complaint, but you may not receive a direct response.
+We will use our discretion in determining when and how to follow up on reported
+incidents, which may range from not taking action to permanent expulsion from
+the project and project-sponsored spaces. We will notify the accused of the
+report and provide them an opportunity to discuss it before any action is taken.
+The identity of the reporter will be omitted from the details of the report
+supplied to the accused. In potentially harmful situations, such as ongoing
+harassment or threats to anyone's safety, we may take action without notice.
+
+## Attribution
+
+This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
+available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..55945c5
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,29 @@
+# How to Contribute
+
+We'd love to accept your patches and contributions to this project. There are
+just a few small guidelines you need to follow.
+
+## Contributor License Agreement
+
+Contributions to this project must be accompanied by a Contributor License
+Agreement. You (or your employer) retain the copyright to your contribution;
+this simply gives us permission to use and redistribute your contributions as
+part of the project. Head over to <https://cla.developers.google.com/> to see
+your current agreements on file or to sign a new one.
+
+You generally only need to submit a CLA once, so if you've already submitted one
+(even if it was for a different project), you probably don't need to do it
+again.
+
+## Code reviews
+
+All submissions, including submissions by project members, require review. We
+use GitHub pull requests for this purpose. Consult
+[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
+information on using pull requests.
+
+## Community Guidelines
+
+This project follows
+[Google's Open Source Community
+Guidelines](https://opensource.google.com/conduct/).
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MANIFEST.in
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e96009b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,10 @@
+vitalsd - Statistics for Embedded Systems
+=========================================
+
+## What is this?
+
+vitalsd is a very simple tool that samples vital system statistics (CPU load,
+free/total memory, temperatures, etc.) and outputs them periodically to a serial
+port. It's designed to be used on embedded systems with physical serial ports
+that can crash in unexpected ways that leave the system in a non-triageable
+state.
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..013bcf5
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,5 @@
+vitalsd (0.0.1-1) UNRELEASED; urgency=low
+
+  * Initial release
+
+ -- June Tate-Gans <jtgans@google.org>  Thu, 27 Dec 2018 14:02:00 -0700
diff --git a/debian/compat b/debian/compat
new file mode 100644
index 0000000..f599e28
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+10
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..aec2de4
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,23 @@
+Source: vitalsd
+Section: python
+Maintainer: AIY Projects <support-aiyprojects@google.com>
+Build-Depends: debhelper,
+               dh-python,
+               python3-all-dev,
+               python3-setuptools
+Priority: optional
+Vcs-Git: https://aiyprojects.googlesource.com/vitalsd
+
+Package: vitalsd
+Section: misc
+Priority: optional
+Architecture: all
+Depends: ${python3:Depends},
+         ${misc:Depends},
+         python3-serial
+Description: A vital statistics monitor that outputs to serial consoles for embedded systems
+ vitalsd is a very simple tool that samples vital system statistics (CPU load,
+ free/total memory, temperatures, etc.) and outputs them periodically to a serial
+ port. It's designed to be used on embedded systems with physical serial ports
+ that can crash in unexpected ways that leave the system in a non-triageable
+ state.
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..936394a
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,7 @@
+Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
+Upstream-Name: vitalsd
+Source: https://aiyprojects.googlesource.com/vitalsd
+
+Files: *
+Copyright: Copyright 2018 Google, LLC <support-aiyprojects@google.com>
+License: Apache-2.0
diff --git a/debian/rules b/debian/rules
new file mode 100755
index 0000000..2218e8f
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,17 @@
+#!/usr/bin/make -f
+# -*- makefile -*-
+
+# Uncomment this to turn on verbose mode.
+# export DH_VERBOSE=1
+
+export PYBUILD_DESTDIR_python3=debian/vitalsd/
+
+%:
+	dh $@ --with python3 --buildsystem=pybuild
+
+override_dh_auto_clean:
+	dh_auto_clean
+	rm -rf mdt/__pycache__
+
+# disable until we have tests to run
+override_dh_auto_test:
diff --git a/man/vitalsd.1 b/man/vitalsd.1
new file mode 100644
index 0000000..e81991d
--- /dev/null
+++ b/man/vitalsd.1
@@ -0,0 +1,19 @@
+.TH VITALSD "1" "December 2018" "MDT" "User Commands"
+.SH NAME
+vitalsd \- daemon to monitor vital system statistics
+.SH SYNOPSIS
+.B vitalsd
+.SH DESCRIPTION
+.PP
+vitalsd is a very simple tool that samples vital system statistics (CPU load,
+free/total memory, temperatures, etc.) and outputs them periodically to a serial
+port. It's designed to be used on embedded systems with physical serial ports
+that can crash in unexpected ways that leave the system in a non-triageable
+state.
+.SH AUTHOR
+Written by June Tate-Gans.
+.SH "REPORTING BUGS"
+Contact AIY Projects support at <support-aiyprojects@google.com>
+.SH COPYRIGHT
+Copyright \(co 2018 Google, Inc.
+License Apache 2.0.
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..9009624
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,42 @@
+from setuptools import setup, find_packages
+from os import path
+from io import open
+
+here = path.abspath(path.dirname(__file__))
+
+with open(path.join(here, 'README.md'), encoding='utf-8') as f:
+    long_description = f.read()
+
+setup(
+    name='vitalsd',
+    version='1.0',
+    description='A vital statistics monitor that outputs to serial consoles for embedded systems',
+    long_description=long_description,
+    long_description_content_type='text/markdown',
+    url='https://aiyprojects.googlesource.com/vitalsd.git',
+    author='Mendel Linux Software Team',
+    author_email='support-aiyprojects@google.com',
+    license='Apache 2',
+    classifiers = [
+        'Development Status :: 3 - Alpha',
+        'Intended Audience :: Developers',
+        'Topic :: Software Development',
+        'Topic :: Utilities',
+        'License :: OSI Approved :: Apache License',
+        'Operating System :: POSIX',
+        'Programming Language :: Python :: 3',
+    ],
+    keywords='embedded development',
+    packages=find_packages(exclude=['contrib', 'docs', 'tests']),
+    python_requires='>=3.5.0',
+    install_requires=[
+    ],
+    data_files=[('share/man/man1', ['man/vitalsd.1'])],
+    package_data={
+    },
+    entry_points={
+        'console_scripts': [
+            'vitalsd=vitalsd.main:main',
+        ],
+    },
+)
diff --git a/vitalsd/__init__.py b/vitalsd/__init__.py
new file mode 100644
index 0000000..b3bdec6
--- /dev/null
+++ b/vitalsd/__init__.py
@@ -0,0 +1,18 @@
+'''
+Copyright 2019 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+'''
+
+
+__version__ = '1.0'
diff --git a/vitalsd/main.py b/vitalsd/main.py
new file mode 100755
index 0000000..94c6d7d
--- /dev/null
+++ b/vitalsd/main.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+
+"""vitalsd - A vital statistics monitoring tool for embedded systems
+
+This is the main CLI dispatch routine that teases out the command line and runs
+the appropriate command.
+
+
+Copyright 2019 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+import sys
+
+from vitalsd.monitor import Monitor
+
+VITALSD_USAGE_HELP = '''
+Usage: vitalsd [<options>]
+
+Where options may be:
+
+'''
+
+
+def main():
+    try:
+        monitor = Monitor()
+        monitor.run()
+    except KeyboardInterrupt:
+        print('Terminating.')
+        exit(1)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/vitalsd/monitor.py b/vitalsd/monitor.py
new file mode 100644
index 0000000..3d6b6fb
--- /dev/null
+++ b/vitalsd/monitor.py
@@ -0,0 +1,33 @@
+import serial
+import sys
+import time
+
+from vitalsd.samplers import cpu
+
+DEFAULT_SAMPLERS = [
+    cpu.UptimeSampler(),
+    cpu.CpuLoadSampler()
+]
+
+class Monitor(object):
+    def __init__(self, delay_secs=10, serial_device='/dev/ttyGS0', speed=115200, bits=8, parity=None, rtscts=None):
+        self.delay_secs = 10
+        self.serial_device = serial_device
+        self.speed = speed
+        self.parity = parity
+        self.rtscts = rtscts
+        self.samplers = DEFAULT_SAMPLERS
+
+    def run(self):
+        with serial.Serial(self.serial_device, self.speed) as port:
+            print('Writing to port {0}'.format(port.name))
+
+            while True:
+                print('Sending {0} samples.'.format(len(self.samplers)))
+                for sampler in self.samplers:
+                    sample = '{0}\n'.format(str(sampler))
+                    port.write(bytes(sample, 'utf-8'))
+                    port.flush()
+
+                print('Sleeping for {0} seconds'.format(self.delay_secs))
+                time.sleep(self.delay_secs)
diff --git a/vitalsd/samplers/__init__.py b/vitalsd/samplers/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vitalsd/samplers/__init__.py
diff --git a/vitalsd/samplers/cpu.py b/vitalsd/samplers/cpu.py
new file mode 100644
index 0000000..3ea22c7
--- /dev/null
+++ b/vitalsd/samplers/cpu.py
@@ -0,0 +1,40 @@
+"""
+Copyright 2019 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+
+from vitalsd.samplers import sampler
+
+
+class UptimeSampler(sampler.Sampler):
+    def name(self):
+        return 'uptime'
+
+    def sample(self):
+        with open('/proc/uptime', 'r') as fp:
+            uptime = fp.readline()
+            uptime = uptime.split(' ')
+            return uptime
+
+
+class CpuLoadSampler(sampler.Sampler):
+    def name(self):
+        return 'loadavg'
+
+    def sample(self):
+        with open('/proc/loadavg', 'r') as fp:
+            loadavg = fp.readline()
+            loadavg = loadavg.split(' ')
+            return loadavg
diff --git a/vitalsd/samplers/sampler.py b/vitalsd/samplers/sampler.py
new file mode 100644
index 0000000..9f62535
--- /dev/null
+++ b/vitalsd/samplers/sampler.py
@@ -0,0 +1,36 @@
+"""
+Copyright 2019 Google LLC
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+"""
+
+
+class Sampler(object):
+    def sample(self):
+        return 'unknown'
+
+    def name(self):
+        return ['unknown']
+
+    def __str__(self):
+        result = [self.name()]
+        result.extend(self.sample())
+        return '\t'.join(result)
+
+
+class MultiSampler(object):
+    def sample(self):
+        return ['unknown']
+
+    def name(self):
+        return [['unknown']]