RaspberryPiでリソースの可視化(NetData版)

提供: ディーズガレージ wiki
移動先: 案内検索

IoT MONITOR

Iot-monitor.jpg

環境

ボード Raspberry Pi 2 Model B
OS Raspbian Stretch Lite 2017-08-16
microSDHC SanDisk Ultra microSDHC Class10 8GB
LAN 標準搭載の有線LAN

イメージ準備

参考: Google検索 - raspberry win32diskimager -
(省略)

入力環境準備

キーボードとモニターとLANを取り付け電源ON

インストール

raspberrypi login: pi
Password: raspberry

$ sudo raspi-config
  7.Advanced Options → A1 Expand Filesystem
  tabでFinishでreboot

raspberrypi login: pi
Password: raspberry

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install raspberrypi-ui-mods
$ sudo apt-get install fonts-vlgothic

$ sudo raspi-config
  3.Boot Options B1 Desktop/CLI → B4 Desktop Autologin
  4.Localisation Options
    I1 Change Locale → ja_JP.UTF-8でスペースキーで*印付けてtabでOK Default locale → ja_JP.UTF-8
    I2 Change Timezone → Asia → Tokyo
    I3 Change Keyboard Layout → Generic 105-key (Intl) PC → Other → Japanese → Japanese → The default for the keyboard layout → No compose key → No
    I4 Change Wi-Fi Country → JP Japan
  tabでFinishでreboot

追加アプリ

参考: Raspberry Pi 3にデスクトップ環境をインストールする
Termitという端末があるのでこれを使ってみる
raspi-configのGUI版

$ sudo apt-get install rc-gui

Text Editor

$ sudo apt-get install leafpad

ターミナル

$ sudo apt-get install lxterminal

ブラウザ

$ sudo apt-get install chromium-browser

圧縮解凍

$ sudo apt-get install xarchiver

RealVNC

$ sudo apt-get install realvnc-vnc-server

ホスト名

ホスト名変更

$ sudo leafpad /etc/hostname

変更

iot

ホスト名変更

$ sudo leafpad /etc/hosts

変更

127.0.1.1 iot

再起動

$ sudo reboot

IP固定

$ sudo leafpad /boot/cmdline.txt

末尾に(スペース空けて)追記

net.ifnames=0
$ sudo leafpad /etc/dhcpcd.conf

末尾に追記(設定内容は各ネットワーク環境により異なります。「Raspberry Pi IP固定」などで検索してみてください。)

interface eth0
static ip_address=192.168.1.187/24
static routers=192.168.1.1
static domain_name_servers=192.168.1.1

再起動

$ sudo reboot

遠隔操作

運用にはモニター、マウス、キーボードは必要ないので、この段階で遠隔操作にしてしまいます。
RealVNCが標準で入ってます。これを使用してみます。

デフォルトで有効になってないので

Menu→設定→RaspberryPiの設定→インターフェイスタブ→VNC有効→OK→再起動

何も考えずディスプレイを取り外しVNCに接続すると画面サイズが656x416となってしまいます。おまじないがあるようなので設定しておきます。

$ sudo leafpad /boot/config.txt
#hdmi_mode=1の下に以下を追加
hdmi_ignore_edid=0xa5000080
hdmi_group=2
hdmi_mode=47

参考: config.txt - Raspberry Pi Documentation

RaspberryPiをシャットダウン

モニター、マウス、キーボードを取り外して電源入れ直し

VNCクライアントから接続してみる
ホスト名で接続する場合、クライアントパソコンにはavahiかBonjourがインストールされている必要があります。
Windowsパソコンだけ問題になりやすく、簡単な方法はiTunesをインストールすることです。
ネット検索で「Raspberry avahi Bonjour」辺りで調べると詳しい事情が出てきます。

RealVNC Viewerの場合
VNC Server: iot.local または 192.168.1.187
Username: pi
Password: raspberry
Confirm: raspberry

成功していれば、以降はVNCクライアントの窓の中で作業できます。

インストール

NetData

参考: Installation · firehol/netdata Wiki · GitHub

$ sudo apt-get update
$ sudo apt-get install zlib1g-dev uuid-dev libmnl-dev gcc make git autoconf autoconf-archive autogen automake pkg-config curl
$ git clone https://github.com/firehol/netdata.git --depth=1
$ cd netdata
$ sudo ./netdata-installer.sh
$ sudo cp system/netdata.service /etc/systemd/system/
$ sudo systemctl daemon-reload
$ sudo systemctl enable netdata
$ sudo service netdata start

設定
参考: netdata for IoT · firehol/netdata Wiki · GitHub

$ sudo leafpad /etc/netdata/netdata.conf

RPi1向け (RPi2とRP3のnetdataのチューニングは必要ないとなってます)

[global]
    history = 600
    update every = 1
    memory mode = ram
    debug log = none
    error log = none
    access log = none
[web]
    enable gzip compression = no
    gzip compression level = 1
[plugins]
    tc = no
    idlejitter = no
    cgroups = no
    apps = no
    node.d = no
    #enable running new plugins = no

sensorsプラグインを有効に(python版は動きませんでしたbash版で対応)

$ sudo leafpad /etc/netdata/charts.d.conf

アンコメント

sensors=force

再起動

$ sudo reboot

動作確認

http://127.0.0.1:19999
またはローカルネット内の他のPCから http://192.168.1.187:19999

設定項目の確認

http://127.0.0.1:19999/netdata.conf
またはローカルネット内の他のPCから http://192.168.1.187:19999/netdata.conf

Nginx

参考: Running behind nginx · firehol/netdata Wiki · GitHub
参考: netdata/python.d at master · firehol/netdata · GitHub

$ sudo apt-get install nginx
$ sudo /etc/init.d/nginx start

デフォルトのシンボリックリンク削除

$ sudo unlink /etc/nginx/sites-enabled/default

設定作成 ※ /etc/nginx/nginx.confでincludeになっているのでhttp{…}ディレクティブは必要無し

$ sudo leafpad /etc/nginx/sites-available/netdata
log_format netdata '$remote_addr - $remote_user [$time_local] '
                '"$request" $status $body_bytes_sent '
                '$request_length $request_time '
                '"$http_referer" "$http_user_agent"';

access_log /var/log/nginx/access.log netdata;

upstream backend {
    # the netdata server
    server 127.0.0.1:19999;
    keepalive 64;
}

server {
    # nginx listens to this
    listen 8081;
    
    # the virtual host name of this
    server_name netdata.example.com;

    location / {
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://backend;
        proxy_http_version 1.1;
        proxy_pass_request_headers on;
        proxy_set_header Connection "keep-alive";
        proxy_store off;
    }
    location /stub_status {
        stub_status on;
        access_log off;
        allow 192.168.1.0/24;
        allow 127.0.0.1;
        deny all;
    }
}

シンボリックリンク

$ sudo ln -s /etc/nginx/sites-available/netdata /etc/nginx/sites-enabled/

再起動

$ sudo reboot

動作確認

http://127.0.0.1:8081
ローカルネット内の他のPCから http://192.168.1.187:8081

アップデートの自動化

インストール

$ sudo apt-get install unattended-upgrades
$ sudo dpkg-reconfigure -plow unattended-upgrades
GUIがでるので「はい」を選択<br />
Origins-Patternの設定はよくわからないのでこのままtab押して了解

設定

$ sudo leafpad /etc/apt/apt.conf.d/50unattended-upgrades

変更箇所(セキュリティーアップデートのみ自動アップデート設定)

//Unattended-Upgrade::Automatic-Reboot "false";
を
Unattended-Upgrade::Automatic-Reboot "true";
に

//Unattended-Upgrade::Automatic-Reboot-Time "02:00";
を
Unattended-Upgrade::Automatic-Reboot-Time "02:00";

再起動

$ sudo reboot

環境センサのPythonプラグイン

NetData環境センサ

環境センサにNetDataのPythonプラグインで接続して値を取得してみます。
請負で作成した関係でNetDataのwikiから得られる以外のコメントは全て省いてます。
参考にする場合ご注意ください。

参考: How to write new module · firehol/netdata Wiki · GitHub

I2Cの有効化

メニュー→設定→RaspberryPiの設定→インターフェイスタブ→I2C有効にチェック
再起動

netdataがI2C通信をするにはi2cグループに追加する必要があるようです

$ sudo adduser netdata i2c

BME280

BME280使用 温湿度・気圧センサモジュールキット

BME280搭載 温湿度・気圧センサモジュール - スイッチサイエンス
BME280使用 温湿度・気圧センサモジュールキット: 秋月電子通商
参考: Raspberry Pi + BME280モジュールで自動で温度・湿度・気圧を測定してグラフ化する -karaage-
秋月電子通商のAE-BME280の場合
配線

J3の半田付けなし
BME280のVDD(Pin1) - RaspberryPiの3.3V(Pin1)
BME280のGND(Pin2) - RaspberryPiのGND(Pin6)
BME280のCSB(Pin3) - RaspberryPiの3.3V(Pin1)
BME280のSDI(Pin4) - RaspberryPiのGPIO2(Pin3)
BME280のSDO(Pin5) - RaspberryPiのGND(Pin6)
BME280のSCK(Pin6) - RaspberryPiのGPIO3(Pin5)

確認

$ sudo apt-get install i2c-tools
$ sudo i2cdetect -y 1
76番があればOK

インストール

$ sudo apt-get install python-smbus

新規作成
参考: スイッチサイエンスのBME280公開リポジトリ(Python、Arduinoのサンプル)

$ sudo leafpad /home/pi/bme280.py
#coding: utf-8

#from smbus2 import SMBus
from smbus import SMBus
import time

bus_number  = 1
i2c_address = 0x76

bus = SMBus(bus_number)

digT = []
digP = []
digH = []

t_fine = 0.0


def writeReg(reg_address, data):
	bus.write_byte_data(i2c_address,reg_address,data)

def get_calib_param():
	calib = []
	
	for i in range (0x88,0x88+24):
		calib.append(bus.read_byte_data(i2c_address,i))
	calib.append(bus.read_byte_data(i2c_address,0xA1))
	for i in range (0xE1,0xE1+7):
		calib.append(bus.read_byte_data(i2c_address,i))

	digT.append((calib[1] << 8) | calib[0])
	digT.append((calib[3] << 8) | calib[2])
	digT.append((calib[5] << 8) | calib[4])
	digP.append((calib[7] << 8) | calib[6])
	digP.append((calib[9] << 8) | calib[8])
	digP.append((calib[11]<< 8) | calib[10])
	digP.append((calib[13]<< 8) | calib[12])
	digP.append((calib[15]<< 8) | calib[14])
	digP.append((calib[17]<< 8) | calib[16])
	digP.append((calib[19]<< 8) | calib[18])
	digP.append((calib[21]<< 8) | calib[20])
	digP.append((calib[23]<< 8) | calib[22])
	digH.append( calib[24] )
	digH.append((calib[26]<< 8) | calib[25])
	digH.append( calib[27] )
	digH.append((calib[28]<< 4) | (0x0F & calib[29]))
	digH.append((calib[30]<< 4) | ((calib[29] >> 4) & 0x0F))
	digH.append( calib[31] )
	
	for i in range(1,2):
		if digT[i] & 0x8000:
			digT[i] = (-digT[i] ^ 0xFFFF) + 1

	for i in range(1,8):
		if digP[i] & 0x8000:
			digP[i] = (-digP[i] ^ 0xFFFF) + 1

	for i in range(0,6):
		if digH[i] & 0x8000:
			digH[i] = (-digH[i] ^ 0xFFFF) + 1  

def readData():
	data = []
	for i in range (0xF7, 0xF7+8):
		data.append(bus.read_byte_data(i2c_address,i))
	pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
	temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
	hum_raw  = (data[6] << 8)  |  data[7]
	
	t =compensate_T(temp_raw)
	p =compensate_P(pres_raw)
	h =compensate_H(hum_raw)
	return t, h, p

def compensate_P(adc_P):
	global  t_fine
	pressure = 0.0
	
	v1 = (t_fine / 2.0) - 64000.0
	v2 = (((v1 / 4.0) * (v1 / 4.0)) / 2048) * digP[5]
	v2 = v2 + ((v1 * digP[4]) * 2.0)
	v2 = (v2 / 4.0) + (digP[3] * 65536.0)
	v1 = (((digP[2] * (((v1 / 4.0) * (v1 / 4.0)) / 8192)) / 8)  + ((digP[1] * v1) / 2.0)) / 262144
	v1 = ((32768 + v1) * digP[0]) / 32768
	
	if v1 == 0:
		return 0
	pressure = ((1048576 - adc_P) - (v2 / 4096)) * 3125
	if pressure < 0x80000000:
		pressure = (pressure * 2.0) / v1
	else:
		pressure = (pressure / v1) * 2
	v1 = (digP[8] * (((pressure / 8.0) * (pressure / 8.0)) / 8192.0)) / 4096
	v2 = ((pressure / 4.0) * digP[7]) / 8192.0
	pressure = pressure + ((v1 + v2 + digP[6]) / 16.0) 
	pressure = pressure  / 100.0 

	#print "pressure : %7.2f hPa" % (pressure/100)
	return pressure

def compensate_T(adc_T):
	global t_fine
	v1 = (adc_T / 16384.0 - digT[0] / 1024.0) * digT[1]
	v2 = (adc_T / 131072.0 - digT[0] / 8192.0) * (adc_T / 131072.0 - digT[0] / 8192.0) * digT[2]
	t_fine = v1 + v2
	temperature = t_fine / 5120.0
	#print "temp : %-6.2f ℃" % (temperature) 
	return temperature

def compensate_H(adc_H):
	global t_fine
	var_h = t_fine - 76800.0
	if var_h != 0:
		var_h = (adc_H - (digH[3] * 64.0 + digH[4]/16384.0 * var_h)) * (digH[1] / 65536.0 * (1.0 + digH[5] / 67108864.0 * var_h * (1.0 + digH[2] / 67108864.0 * var_h)))
	else:
		return 0
	var_h = var_h * (1.0 - digH[0] * var_h / 524288.0)
	if var_h > 100.0:
		var_h = 100.0
	elif var_h < 0.0:
		var_h = 0.0
	#print "hum : %6.2f %" % (var_h)
	return var_h


def setup():
	osrs_t = 1			#Temperature oversampling x 1
	osrs_p = 1			#Pressure oversampling x 1
	osrs_h = 1			#Humidity oversampling x 1
	mode   = 3			#Normal mode
	t_sb   = 5			#Tstandby 1000ms
	filter = 0			#Filter off
	spi3w_en = 0			#3-wire SPI Disable

	ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode
	config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en
	ctrl_hum_reg  = osrs_h

	writeReg(0xF2,ctrl_hum_reg)
	writeReg(0xF4,ctrl_meas_reg)
	writeReg(0xF5,config_reg)


setup()
get_calib_param()


if __name__ == '__main__':
	try:
		readData()
	except KeyboardInterrupt:
		pass

TSL2561

Adafruit TSL2561 デジタル光センサ

Adafruit TSL2561 デジタル光センサ - スイッチサイエンス
TSL2561使用 照度センサーモジュール: 秋月電子通商
参考: Raspberry pi 2でTSL2561を使ってpythonで照度を取得する -いなばのメモ-
参考: RaspberryPI3で照度センサー(TSL2561)を使ってみる -40歳から始めるブログ -

配線

TSL2561の3vo(Pin3) - RaspberryPiの3.3V(Pin1)
TSL2561のSDA(Pin6) - RaspberryPiのGPIO2(Pin3)
TSL2561のSCL(Pin7) - RaspberryPiのGPIO3(Pin5)
TSL2561のGND(Pin2) - RaspberryPiのGND(Pin6)

確認

$ sudo i2cdetect -y 1
39番があればOK

新規作成

$ sudo leafpad /home/pi/tsl2561.py
#! /usr/bin/python2
#coding: UTF-8

import smbus
import time
import math

bus = smbus.SMBus(1)        #I2cバス番号
address = 0x39              #I2Cアドレス
command = 0x00

#i2c データ出力 1byte
def write(regist, value):
    bus.write_byte_data(address, regist, value)

#i2c データ読み込み 1byte
def read(regist):
    value = bus.read_byte_data(address, regist)
    return value

#i2c データ読み込み ブロック
def blockread(regist, num):
    value = bus.read_i2c_block_data(address, regist, num)
    return value

def ratio_calc(ambient, ir):
    # Avoid division by zero
    if (float(ambient) == 0):
        ratio = 9999
    else:
        ratio = (ir / float(ambient))

    return ratio

def init():
    #read ID
#    print("id_reg=0x{0:02x}".format(read(0x8A)))
    #device enable
    write(0x80,0x03)
    power = 0x03
    while power != 0x03:
        power = read(0x80) & 0x03
        print("{0:02x}".format(power))
    #print("reg=0x{0:02x}".format(read(0x80)))

    #gain setting
    write(0x81,0x11)
#    print("reg=0x{0:02x}".format(read(0x81)))

def read_lux():
    value0 = blockread(0xAC,2)
    ch0 = 256*value0[1]+value0[0]
#    print("reg=0x{0:04x}".format(ch0))

    value1 = blockread(0xAE,2)
    ch1 = 256*value1[1]+value1[0]
#    print("reg=0x{0:04x}".format(ch1))

    ratio = ratio_calc(ch0,ch1)
    if ((ratio >= 0) & (ratio <= 0.52)):
        lux = (0.0315 * ch0) - (0.0593 * ch0 * (ratio**1.4))
    elif (ratio <= 0.65):
        lux = (0.0229 * ch0) - (0.0291 * ch1)
    elif (ratio <= 0.80):
        lux = (0.0157 * ch0) - (0.018 * ch1)
    elif (ratio <= 1.3):
        lux = (0.00338 * ch0) - (0.0026 * ch1)
    elif (ratio > 1.3):
        lux = 0

    return lux

def main():
    init()
    counter = 0
    lux = read_lux()

    while True:
       lux = read_lux()
       print("lux={0:f}".format(lux))

       time.sleep(1.0)

if __name__ == '__main__':
    main()

EnvSensors.chart.py

$ sudo leafpad /usr/libexec/netdata/python.d/EnvSensors.chart.py
# -*- coding: utf-8 -*-
# Description: example netdata python.d module
# Author: Pawel Krupa (paulfantom)

import sys
sys.path.append('/home/pi/')
import bme280
import tsl2561
from base import ExecutableService

# update_every = 1
# priority = 60000
# retries = 60

ORDER = ['temperature', 'humidity', 'pressure', 'lux']

CHARTS = {
    'temperature': {
        'options': [None, 'temperature', '℃', 'temperature', 'environment.temperature', 'line'],
        'lines': [
            ['temp', 'temperature', 'absolute', 1, 100]
        ]},
    'humidity': {
        'options': [None, 'humidity', '%', 'humidity', 'environment.humidity', 'line'],
        'lines': [
            ['hum', 'humidity', 'absolute', 1, 100]
        ]},
    'pressure': {
        'options': [None, 'pressure', 'hPa', 'pressure', 'environment.pressure', 'line'],
        'lines': [
            ['press', 'pressure', 'absolute', 1, 100]
        ]},
    'lux': {
        'options': [None, 'lux', 'lux', 'lux', 'environment.lux', 'line'],
        'lines': [
            ['lux', 'lux', 'absolute', 1, 100]
        ]}
}

class Service(ExecutableService):
    def __init__(self, configuration=None, name=None):
        ExecutableService.__init__(self, configuration=configuration, name=name)
        self.order = ORDER
        self.definitions = CHARTS
    
    def check(self):
        return True
    
    def _get_data(self):
        try:
            raw01 = bme280.readData()
            raw02 = tsl2561.read_lux()
            return {'temp': raw01[0] * 100,
                    'hum': raw01[1] * 100,
                    'press': raw01[2] * 100,
                    'lux': raw02 * 100}
        except (ValueError, AttributeError):
            return None

EnvSensors.conf

$ sudo leafpad /etc/netdata/python.d/EnvSensors.conf
# netdata python.d.plugin configuration for example
#
# This file is in YaML format. Generally the format is:
#
# name: value
#
# There are 2 sections:
#  - global variables
#  - one or more JOBS
#
# JOBS allow you to collect values from multiple sources.
# Each source will have its own set of charts.
#
# JOB parameters have to be indented (using spaces only, example below).

# ----------------------------------------------------------------------
# Global Variables
# These variables set the defaults for all JOBs, however each JOB
# may define its own, overriding the defaults.

# update_every sets the default data collection frequency.
# If unset, the python.d.plugin default is used.
update_every: 1

# priority controls the order of charts at the netdata dashboard.
# Lower numbers move the charts towards the top of the page.
# If unset, the default for python.d.plugin is used.
priority: 60000

# retries sets the number of retries to be made in case of failures.
# If unset, the default for python.d.plugin is used.
# Attempts to restore the service are made once every update_every
# and only if the module has collected values in the past.
retries: 60

# ----------------------------------------------------------------------
# JOBS (data collection sources)
#
# The default JOBS share the same *name*. JOBS with the same name
# are mutually exclusive. Only one of them will be allowed running at
# any time. This allows autodetection to try several alternatives and
# pick the one that works.
#
# Any number of jobs is supported.
#
# All python.d.plugin JOBS (for all its modules) support a set of
# predefined parameters. These are:
#
# job_name:
#     name: myname     # the JOB's name as it will appear at the
#                      # dashboard (by default is the job_name)
#                      # JOBs sharing a name are mutually exclusive
#     update_every: 1  # the JOB's data collection frequency
#     priority: 60000  # the JOB's order on the dashboard
#     retries: 5       # the JOB's number of restoration attempts
#
# Additionally to the above, example also supports the following:
#
# - none
#
# ----------------------------------------------------------------------
# AUTO-DETECTION JOBS
# only one of them will run (they have the same name)

デバッグ

$ sudo -u netdata /usr/libexec/netdata/plugins.d/python.d.plugin 1 debug EnvSensors

登録

$ sudo leafpad /etc/netdata/python.d.conf

末尾に

EnvSensors: yes

を追記

確認

$ sudo systemctl stop netdata
$ sudo systemctl start netdata

ブラウザでnetdataを開きEnvSensorsの項目があれば動いています

FLiR サーモグラフィ

FLiR開発キット
数ヶ月試した感じでは不定期に落ちる現象がありました。現状お勧めできない感じです。

サーバファームのサーモグラフィ監視カメラを作ってみます。

準備

参考: FLiR開発キット - スイッチサイエンス
参考: FLIR Lepton Hookup Guide - learn.sparkfun.com
参考: groupgets/LeptonModule Wiki · GitHub

SPI通信を使用してビデオストリームを送信し、制御インターフェイスはI2C通信プロトコルを使用だそうです。

配線

FLIRのCS(Pin1) - RaspberryPiのGPIO7(Pin26)
FLIRのMOSI(Pin2) - RaspberryPiのGPIO10(Pin19)
FLIRのMISO(Pin3) - RaspberryPiのGPIO9(Pin21)
FLIRのCLK(Pin4) - RaspberryPiのGPIO11(Pin23)

FLIRのGND(Pin5) - RaspberryPiのGND(Pin6)
FLIRのVIN(Pin6) - RaspberryPiの3.3V(Pin1)
FLIRのSDA(Pin7) - RaspberryPiのGPIO2(Pin3)
FLIRのSCL(Pin8) - RaspberryPiのGPIO3(Pin5)

SPIとI2C有効

メニュー→設定→RaspberryPiの設定→インターフェイスタブ→SPIとI2Cを有効にチェック
再起動

確認

$ sudo i2cdetect -y 1
2a番があればOK

FLIR Lepton Hookup Guide - learn.sparkfun.comを参考に映像が映る状況を作る
「LeptonSDKを作る必要があるのでLeptonSDKEmb32PUBディレクトリでmake」ってあるけど要らない気がする

raspberrypi_videoを試してみる
参考: LeptonModule/software/raspberrypi_video at master · groupgets/LeptonModule · GitHub

$ sudo apt-get install qt4-dev-tools
$ sudo apt-get install git
$ cd ~
$ git clone https://github.com/groupgets/LeptonModule.git
$ cd /home/pi/LeptonModule/software/raspberrypi_video
$ qmake && make
$ sudo ./raspberrypi_video

Raspberrypi video.png
sparkfun.comのチュートリアルと同じエラー表示
対処方法は「ブレークアウトボードから慎重に取り外してもう一度慎重に取り付ける!?」なんだこれ??

raspberrypi_captureも試してみる
参考: GitHub - groupgets/LeptonModule: Code for getting started with the FLIR Lepton breakout board

$ cd /home/pi/LeptonModule/software/raspberrypi_capture/
$ gcc raspberrypi_capture.c
$ sudo ./a.out
raspberrypi_captureディレクトリに画像出来たけど??

raspberrypi_qtも試してみる
参考: LeptonModule/software/raspberrypi_qt at master · groupgets/LeptonModule · GitHub

$ cd /home/pi/LeptonModule/software/raspberrypi_qt/
$ qmake && make
$ sudo ./raspberrypi_qt

Raspberrypi qt.png
安定した映像きた!

V4L2Lepton

参考: LeptonModule/software/v4l2lepton at master · groupgets/LeptonModule · GitHub
Webカメラにしたいだけなんですが面倒な感じ。

1. rpi-sourceユーティリティを使用してカーネルヘッダーをインストール
2. v4l2loopbackをコンパイル
3. ステップ2が成功したら、ソースディレクトリにv4l2loopback.koがあるはず
4. v4l2loopback.koを/lib/modulesにコピー
(/lib/modulesディレクトリでうまく動作しない場合は/lib/modules/$(uname -r)に入れるか、または両方に入れる)
5. depmod実行 $ sudo depmod -a
6. v4l2leptonをコンパイル $ make
7. v4l2leptonを実行 $ ./v4l2lepton /dev/videoX (Xは数字、カメラ1台なら0)

1.rpi-source
sudo apt-get install raspberrypi-kernel-headersで対応できるかと思ったら古いものが入ってしまったので素直にLeptonに従う
WIKIではPi1andPi2になってますがPi3のStretchで使えました。

$ cd ~
$ sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source && sudo chmod +x /usr/bin/rpi-source && /usr/bin/rpi-source -q --tag-update
$ rpi-source
ERROR:
gcc version check failed: could not extract version numbers
Skip this check with --skip-gcc
$ rpi-source --skip-gcc

環境によるけど/lib/modules/4.9.47-v7+にbuildディレクトリがシンボリックリンクされv4l2loopbackのコンパイルに必要な感じ

2~5. v4l2loopbackをコンパイル
Leptonに従うとおかしくなるのでv4l2loopbackに従う

$ cd ~
$ git clone https://github.com/umlaeute/v4l2loopback.git
$ cd /home/pi/v4l2loopback
$ make
$ sudo make install
$ sudo depmod -a
$ sudo modprobe v4l2loopback

/dev/video0があればOK

6. v4l2leptonをコンパイル

$ cd /home/pi/LeptonModule/software/v4l2lepton
$ make

7. v4l2leptonを実行

$ ./v4l2lepton /dev/video0
Waiting for sink
done reading, resets:

動いた?
公式では「VLC Media Playerのようなものを使用し、キャプチャデバイスとして/dev/videoXを開くことで、ストリームが動作していることを確認できます。」とあるのでVLCの用意。

Ctrl+Cで一旦停止
$ sudo apt-get install vlc

確認

$ cd /home/pi/LeptonModule/software/v4l2lepton
$ ./v4l2lepton /dev/video0
Waiting for sink
done reading, resets:
VLC起動→メディア→キャプチャーデバイス→ビデオデバイス名に/dev/video0→再生

V4l2lepton.png
成功!

確認

$ v4l2-ctl -d /dev/video0 --all

80x60pixel 30fps RGB3 sRGB

pyleptonも用意してくれてますが安定したので省略
参考: GitHub - groupgets/pylepton: Quick and dirty pure python library for interfacing with FLIR lepton

メモ: rpi-sourceを使う理由、v4l2loopbackの説明にもありますが「カーネルモジュールを構築するには、モジュールを使用するLinuxカーネルと一致するカーネルヘッダーをインストールする必要があります。」が原因で、例えばPi3で構築した環境をPi2で使うとv4l2loopbackがエラーになることがありました。エラー内容の参照先見るとなるほどといった内容です。/home/pi/linux-*************ディレクトリを削除してrpi-sourceからやり直したら動きました。
もっと分かりやすい所で、/lib/modules/4.9.**-**/extraの中にv4l2loopback.koができるのでバージョンが違うと即互換性が無くなる感じです。

私見

映像取得が不安定で多くの方が悩まれてると想像します。私見列記しておきます。(勘違いもあると思います。)

  • 接続確認にraspberrypi_videoは不安定すぎる。raspberrypi_qtの方がいい。(pylepton試してません。)
  • 全く映像が出ない場合、シャットダウンして電源も抜き10秒程度待ってから電源投入すると成功率がグッと上がる。
  • 15cm程度から30cm程度のジャンパケーブルに変えたら全く映像が出なかった。(接触不良など他の要因もありそうですが…。)
  • BME280とTSL2561とFLiRセンサ3個同時使用がどうしても出来なかった。GPIOのチュートリアル読むと流せる電流量の制限などあるのでデリケートな状況を予想してます。
  • ↑であれば3.3Vの口が他にもあるから変えてみましたが効果見えずでした。GPIOの変更は試してません。

GStreamer

インストール

$ sudo apt-get install gstreamer1.0-*

確認

$ gst-inspect-1.0

RAMディスク

配信ディレクトリ

$ sudo mkdir /var/www/html/stream

配信ディレクトリのRAMディスク化

$ sudo leafpad /etc/fstab

末尾に追記

tmpfs /var/www/html/stream tmpfs defaults,size=100m,noatime,mode=0755 0 0

RAMディスク起動設定

$ sudo leafpad /etc/rc.local

末尾exit 0の手前に追記

mkdir -p /var/www/html/stream

再起動

$ sudo reboot

Nginx修正

コンフィグを修正します。
映像がCORSに該当するようで、未設定のままではCANVAS汚染する恐れがあります。
(通常は汚染しない使い方が正しいと思います。)
都合が悪いのでnginxにCORSヘッダ情報を付加するポート指定のリバースプロキシを設定します。
小細工しないならlisten 8086のserver { ~ }を消せば動くと思います。
注意
InfluxDBはデフォルトで 8083, 8086, 8090, 8099番のポートを使用
Grafanaはデフォルトで 3000番のポートを使用

$ sudo leafpad /etc/nginx/sites-available/netdata
log_format netdata '$remote_addr - $remote_user [$time_local] '
				'"$request" $status $body_bytes_sent '
				'$request_length $request_time '
				'"$http_referer" "$http_user_agent"';

access_log /var/log/nginx/access.log netdata;

upstream backend {
	server 127.0.0.1:19999;
	keepalive 64;
}

server {
	listen 8081;
	server_name netdata.example.com;
	
	location / {
		proxy_set_header X-Forwarded-Host $host;
		proxy_set_header X-Forwarded-Server $host;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_pass http://backend;
		proxy_http_version 1.1;
		proxy_pass_request_headers on;
		proxy_set_header Connection "keep-alive";
		proxy_store off;
	}
	location /stub_status {
		stub_status on;
		access_log off;
		allow 192.168.1.0/24;
		allow 127.0.0.1;
		deny all;
	}
}

server {
	listen 80;
	root /var/www/html;

}

server {
	listen 8087;
	server_name localhost;
	charset UTF-8;
	
	location /stream/ {
		proxy_http_version 1.1;
		proxy_pass http://127.0.0.1/stream/;
		add_header Access-Control-Allow-Origin *;
		add_header Access-Control-Allow-Methods "POST, GET, OPTIONS";
		add_header Access-Control-Allow-Headers "Origin, Authorization, Accept";
		add_header Access-Control-Allow-Credentials true;
	}
}

再起動

$ sudo reboot

確認

RAMディスク確認

$ df -h | grep /var/www/html/stream

HLS起動確認

$ sudo modprobe v4l2loopback
$ cd /home/pi/LeptonModule/software/v4l2lepton
$ ./v4l2lepton /dev/video0
もう一つターミナル開いて
$ sudo gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw,width=80,height=60,framerate=30/1 ! videoscale method=1 ! video/x-raw,width=320,height=240 ! omxh264enc control-rate=1 target-bitrate=5000000 ! video/x-h264,profile=baseline ! h264parse ! mpegtsmux ! hlssink max-files=10 target-duration=8 location=/var/www/html/stream/stream-%08d.ts playlist-location=/var/www/html/stream/stream.m3u8

メモ: GStreamer-CRITICAL **: gst_segment_to_running_time: assertion 'segment->format == format' failed がときどき出る(動くのでとりあえず無視)
/var/www/html/streamに映像データが作られていればOK
VLCで確認

VLC起動→ネットワークストリームを開く→http://192.168.1.188/stream/stream.m3u8→再生

ブラウザで確認

$ sudo leafpad /var/www/html/index.html

参考: GitHub - video-dev/hls.js: JavaScript HLS client using Media Source Extension

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>test</title>
<style>
* {
	margin: 0;
	padding: 0;
}
body {
	background: #333;
}
#wrapper {
	position: absolute;
	width: 100%;
	height: 100%;
}
#video {
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: auto;
	width: 320px;
	height: 240px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
$(function() {
	if (Hls.isSupported()) {
		var video = document.getElementById('video');
		var hls = new Hls();
		hls.loadSource('http://192.168.1.187/stream/stream.m3u8');
		hls.attachMedia(video);
		hls.on(Hls.Events.MANIFEST_PARSED, function() {
			video.play();
		});
	}
});
</script>
</head>
<body>
<div id="wrapper">
	<video id="video"></video>
</div>
</body>
</html>
http://192.168.1.187

起動スクリプト

書き込み中

複数台集約

サーバファームのテレメトリを一箇所に集約してみます。

参考: Replication Overview · firehol/netdata Wiki · GitHub
参考: Monitoring ephemeral nodes · firehol/netdata Wiki · GitHub
参考: netdata のレプリケーション設定(stream) - biaxident’s blog

マスターの設定

マスターにするRaspberryPiに最低限、ホスト名IP固定NetDataのインストールnginxのインストールを設定

$ sudo leafpad /etc/netdata/stream.conf

末尾に追記

[11111111-2222-3333-4444-555555555555]
enabled = yes
default history = 600
default memory = ram
health enabled by default = auto
メモ: api keyは何でもOKとなってますがapi keyとIPアドレスが外部に漏れた場合、NetDataの脆弱を攻撃できる状況が成立すると思います。11111111-2222-3333-4444-555555555555は使わないほうが安全と思います。

再起動

$ sudo reboot

スレーブの設定

スレーブにするRaspberryPiに最低限、ホスト名NetDataのインストールを設定
スレーブが複数台なら複数台に同じ設定でOK

$ sudo leafpad /etc/netdata/stream.conf

末尾に追記(destinationはマスターの固定IPアドレス)

[stream]
enabled = yes
destination = 192.168.1.187:19999
api key = 11111111-2222-3333-4444-555555555555
$ sudo leafpad /etc/netdata/netdata.conf

書き換え

[global]
    history = 300
    update every = 1
    memory mode = none
    debug log = none
    error log = none
    access log = none
[web]
    enable gzip compression = no
    gzip compression level = 1
    mode = none
[health]
    enabled = no

再起動

$ sudo reboot

確認
マスターのIPアドレス

http://192.168.1.187

左上から機器の切り替え

メール設定

サーバファームのテレメトリを集約したマスターにメール設定してみます。
health monitoringで沢山の監視ができますが単純にスレーブの死活監視する場合ズバリのものは無いように見えます。
近いものでfpingプラグイン。これを有効にしてメール設定してみます。

参考: fping Plugin · firehol/netdata Wiki · GitHub
参考: email notifications · firehol/netdata Wiki · GitHub

$ sudo leafpad /etc/netdata/fping.conf

末尾に追記(環境により内容は異なります)

fping="/usr/local/bin/fping"
hosts="iot seti fr24 livebot3 flir"
ping_every = 60000

sendmailコマンドが使えるMTAが必要とあるので
Gmail(二段階認証)にメールするだけの簡単なものネット検索してsSMTPにしてみます。

$ sudo apt-get install ssmtp
$ sudo apt-get install mailutils
$ sudo leafpad /etc/ssmtp/ssmtp.conf

全てコメントアウトしておいて末尾に追記
二段階認証の場合、アプリパスワードを発行しpasswordに貼り付け
Gmailの場合UseSTARTTLSが必要

root=xxxxx@gmail.com
mailhub=smtp.gmail.com:587
AuthUser=xxxxx@gmail.com
AuthPass=password
UseSTARTTLS=YES

送信テスト

$ mail *****@gmail.com
Cc:
Subject:test.
This is test.
「.」もしくはCtrl+Dで送信
$ sudo leafpad /etc/netdata/health_alarm_notify.conf
# email global notification options辺りにgmail追記

確認

$ sudo su -s /bin/bash netdata
$ /usr/libexec/netdata/plugins.d/alarm-notify.sh test [ROLE]

再起動

$ sudo reboot

Pi Zero、Pi 1辺りから沢山メール来ます。耐えられない使い方してそうです。
カスタマイズは様子見してます。

Grafana

サーバファームのテレメトリを集約したマスターにGrafanaをインストールしてみます。

NetData

参考: netdata backends · firehol/netdata Wiki · GitHub

$ sudo leafpad /etc/netdata/netdata.conf
[backend]
    enabled = yes
    data source = average
    type = opentsdb
    destination = localhost:4242
    prefix = netdata
    hostname = iot
    update every = 10
    buffer on failures = 10
    timeout ms = 20000

再起動

$ sudo reboot

InfluxDB

参考: InfluxData | Documentation | Installation

$ curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add -
$ source /etc/os-release
$ test $VERSION_ID = "7" && echo "deb https://repos.influxdata.com/debian wheezy stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
$ test $VERSION_ID = "8" && echo "deb https://repos.influxdata.com/debian jessie stable" | sudo tee /etc/apt/sources.list.d/influxdb.list
$ sudo apt-get update && sudo apt-get install influxdb
$ sudo service influxdb start
$ sudo leafpad /etc/influxdb/influxdb.conf

末尾に追記

[[opentsdb]]
    enabled = true
    bind-address = ":4242"
    database = "netdata"

再起動

$ sudo reboot

保存期間の設定

$ influx
# 作成済みのデータベース確認
> SHOW DATABASES

# ポリシーtrafficを設定(1週間保存し古いものは自動的に削除)
> CREATE RETENTION POLICY traffic ON netdata DURATION 1w REPLICATION 1 DEFAULT

# ポリシーの確認
> SHOW RETENTION POLICIES ON "netdata"

# ポリシー変更
> ALTER RETENTION POLICY traffic ON netdata DURATION 2h

# 終了
> exit

再起動

$ sudo reboot

Grafana

Grafana

参考: fg2it/grafana-on-raspberry Wiki · GitHub

For raspberry pi 1, use

$ sudo apt-get install adduser libfontconfig
$ sudo apt-get install apt-transport-https curl

$ curl https://bintray.com/user/downloadSubjectPublicKey?username=bintray | sudo apt-key add -
$ echo "deb https://dl.bintray.com/fg2it/deb-rpi-1b jessie main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt-get update
$ sudo apt-get install grafana
$ sudo systemctl enable grafana-server
$ sudo systemctl start grafana-server

For raspberry pi 2 and pi 3, use

$ sudo apt-get install adduser libfontconfig
$ sudo apt-get install apt-transport-https curl

$ curl https://bintray.com/user/downloadSubjectPublicKey?username=bintray | sudo apt-key add -
$ echo "deb https://dl.bintray.com/fg2it/deb jessie main" | sudo tee -a /etc/apt/sources.list.d/grafana.list
$ sudo apt-get update
$ sudo apt-get install grafana
$ sudo systemctl enable grafana-server
$ sudo systemctl start grafana-server

再起動

$ sudo reboot

Grafana起動

http://127.0.0.1:3000
またはローカルネット内の他のPCから http://192.168.1.187:3000
User: admin
Password: admin

Home Dashboardが表示されます。
Grafana左上アイコン→Data Sources→Add data source

Grafana-002.jpg

Dashboard for netdataのインポート

https://grafana.com/dashboards/1295
Dashboard for netdata. Netdata used as collector and InfluxDB as data source.
Just change yourhostname in json file and you ready to go!

NetDataのダッシュボード。Netdataはコレクタとして使用され、InfluxDBはデータソースとして使用されます。
jsonファイルのyourhostnameを変更するだけで準備が整っています。

jsonの書き換えがややこしい部分があるので使ってるjsonはこちら

http://dz.plala.jp/wiki_data/iot-1503772301769.zip

netdataのSystemOverviewと温度センサを登録してあります。
一週間表示、JST表示、編集不可、アラート設定なしにしてます。
iotというホスト値にしてるのでテキストエディターなどで全置換してしまえば他のホスト名でも使用できると思います。

Grafana左上アイコン→Dashboards→Import
Upload .json Fileでファイル選択
InfluxDBにnetdata指定しImportボタン
Grafana-005.jpg

InfluxDBに全てのスレーブのデータも登録されてます。
jsonのホスト値iotを他のスレーブ名に書き換え全てインポート

Grafana 追記1

Home Dashboardを無駄に感じ削除方法を公式探しても分からず設定できた手法です。

1. デフォルトで表示させたいDashboardを表示させ左上の☆をクリックして★に
2. 左上メニューのadmin(Main Org.)のProfile
3. PreferencesのHome Dashboardで★にしたDashboardを選択
4. 左上メニューのadmin(Main Org.)のPreferences
5. ここでもPreferencesのHome Dashboardで★にしたDashboardを選択

Grafana 追記2

閲覧のみに制限したAnonymousの設定方法を公式探しても分からず設定できた手法です。

  • 大雑把な理解では、全ての設定はadminで行う
  • ログイン状態であれば左上メニューのadmin(Main Org.)のSwitch to *****でAnonymousに切り替え
  • ↑ただしログイン状態なのでadminとしてAnonymousを見ている状態(=編集可)
  • ログアウトしてGrafanaを開くとAnonymousのDashboardに飛ばされる
  • ↑HomeDashboardに飛ばされるので「Grafana 追記1」の設定をしておけば一発で表示したいDashboardを表示できる
  • ログインしたいならこの状態からサインインのボタン
$ sudo leafpad /etc/grafana/grafana.ini

200行辺りのAnonymous Authを書き換え(garafana.iniでは;もコメントアウトの意味です)

[auth.anonymous]
# enable anonymous access
enabled = true

# specify organization name that should be used for unauthenticated users
org_name = Anonymous

# specify role for unauthenticated users
org_role = Viewer

再起動

$ sudo systemctl restart grafana-server

左上メニューのadmin(Main Org.)の+ New organization
Anonymousと入力してCreate
以降はログイン状態でSwitch to Anonymousで通常のDashboard作成
完了したらログアウトしてGrafanaがAnonymousで表示するか確認

※外部に公開する場合、ユーザー名:admin、パスワード:adminは脆弱になるのでadminのパスワード変更必要と思います。

Grafana 追記3

InfluxDBはデフォルトで 8083, 8086, 8090, 8099番のポートを使用
Grafanaはデフォルトで 3000番のポートを使用
nginxの8080番から8086番辺りまで使ったら気が付きました。

IoT MONITOR

サーバファーム横断型のダッシュボード作ってみます。

IoT MONITOR

Iot-monitor.jpg

設置場所はどこでも構わないがマスターのjsonが取れる位置に居る必要あり。
スレーブのjsonはマスターのプロキシで到達できるので、マスター・スレーブ間が開通していれば考慮する必要無し。

index.html

<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta http-equiv="Expires" content="0">
<link rel="apple-touch-icon" sizes="180x180" href="favicon/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon/favicon-16x16.png">
<link rel="manifest" href="favicon/manifest.json">
<link rel="mask-icon" href="favicon/safari-pinned-tab.svg" color="#5bbad5">
<link rel="shortcut icon" href="favicon/favicon.ico">
<meta name="msapplication-config" content="favicon/browserconfig.xml">
<meta name="theme-color" content="#ffffff">
<title>IoT MONITOR</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
@import url(//fonts.googleapis.com/earlyaccess/notosansjp.css);
@font-face {
 font-family: 'AyatoNumA_eot';
 src: url('AyatoNumA.eot');
}
@font-face {
 font-family: 'AyatoNumA_ttf';
 src: url('AyatoNumA.ttf') format("truetype");
}
* {
	margin: 0;
	padding: 0;
}
html, body {
	font-family: ‘Noto Sans Japanese’, sans-serif;
	height: 100%;
	width: 100%;
	background-color: #262626;
	color: #fff;
	text-align: center;
}
a, a:focus, a:hover {
	outline: none;
}
.close {
	font-size: 26px;
}
.clear {
	clear: both;
}
.dummy {
	height: 40px;
}
.navbar {
	min-height:28px !important;
	margin-right: auto;
	margin-left: auto;
	background: #ffa020;
}
.navbar-nav {
	margin-top: 0;
	margin-bottom: 0;
}
.brand {
	float: left;
    height: 30px;
	padding: 8px 0 0 5px !important;
	color: #66400d !important;
	font-style: normal;
	font-weight: bold;
	font-size: 12px;
}
.nav {
	float: right;
    height: 30px;
	font-style: normal;
	font-size: 12px;
}
.nav>li {
	float: right;
}
.nav>li>span {
	display: block;
	padding: 8px 12px 0 15px !important;
	cursor: pointer;
	color: #333 !important;
}
#smoke {
	position: fixed;
	top: 0;
	left: 0;
	opacity: 0.6;
}
.wrapper {
	display: table;
	width: 100%;
	height: 100%;
	min-height: 100%;
	opacity: 0;
	background: #0a0807;
	background: -moz-linear-gradient(top,  #0a0807 20%, #1e1b16 50%, #38312c 100%);
	background: -webkit-linear-gradient(top,  #0a0807 20%,#1e1b16 50%,#38312c 100%);
	background: linear-gradient(to bottom,  #0a0807 20%,#1e1b16 50%,#38312c 100%);
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0a0807', endColorstr='#38312c',GradientType=0 );
}
.wrapper-inner {
	display: table-cell;
	vertical-align: middle;
}
.wrapper-container, .navbar-container {
	margin-right: auto;
	margin-left: auto;
}
.brand, .hard, .hardSub, .gauge-container, .gauge, .title, .label, .units, .alert, .senstitle, .envText {
	-ms-user-select: none;
	-webkit-user-select: none;
	-moz-user-select: none;
	cursor: default;
	position: relative;
	z-index: 10;
}
.gauge-container {
	float: left;
}
.gauge {
	position: relative;
}
canvas {
	position: absolute;
	top: 0;
	left: 0;
}
.title, .label, .units {
	position: absolute;
	left: 0;
	right: 0;
}
.title {
	font-size: 11px;
	color: #907171;
}
.label {
	font-family: 'AyatoNumA_eot', 'AyatoNumA_ttf';
	font-style: normal;
	font-weight: normal;
	font-size: 20px;
	color: #ffa020;
}
.units {
	font-size: 11px;
	color: #907171;
}
.alert {
	position: absolute;
	opacity: 0;
	-webkit-border-radius: 50%;
	-moz-border-radius: 50%;
	border-radius: 50%;
	background-color: red;
}
.back {
	position: absolute;
	left: 9px;
	top: 9px;
	width: 88px;
	height: 88px;
	opacity: 0.1;
	-webkit-border-radius: 50%;
	-moz-border-radius: 50%;
	border-radius: 50%;
	background-color: gray;
}
.hard {
	margin-left: 5px;
	color: #ffa020;
	text-align: left;
}
.hardSub {
	margin-left: 5px;
	color: #907171;
}
#infoicon {
	position: absolute;
	right: 19px;
	top: 19px;
	z-index: 10000;
	cursor: pointer;
}
#fullscreen {
	position: absolute;
	right: 46px;
	top: 20px;
	z-index: 10000;
	cursor: pointer;
}
#netdataicon {
	position: absolute;
	right: 71px;
	top: 20px;
	z-index: 10000;
	cursor: pointer;
}
#grafanaicon {
	position: absolute;
	right: 96px;
	top: 19px;
	z-index: 10000;
	cursor: pointer;
}
#tvicon {
	position: absolute;
	right: 125px;
	top: 18px;
	z-index: 10000;
	cursor: pointer;
}
.modal-content {
	background: rgba(0,0,0,0);
}
.modal-header {
	border-bottom: 0px solid #e5e5e5;
	padding-bottom: 0px;
}
.modal-body {
	text-align: left;
	color: #a78686;
	line-height: 20px;
	border-radius: 8px;
	background: #222;
}
.modal-dialog {
	float: left;
	text-align: left;
}
.modal-open .modal {
	overflow-y: hidden;
}
.href {
	cursor: pointer;
	color: #aaa;
}
.modal-body .href{
	font-weight: bold;
}
#infoModal .modal-dialog, #infoModal .modal-body {
	width: 550px;
	height: 100px;
}
#video, #videoModal .modal-dialog, #videoModal .modal-body, #noise {
	width:320px;
	height:240px;
	padding:0px;
}
.modal-backdrop.in, .modal-backdrop.fade {
	opacity: 0;
}
@media screen and (min-width: 768px) { 
  #infoModal:before {
	float: left;
  }
}
.close, .close:hover {
	position: absolute;
	right: -17px;
	top: -14px;
	z-index: 100;
	font-size: 0;
	opacity: 1.0;
}
#video_off, #video_on {
	position: absolute;
	right: 10px;
	top: 10px;
	z-index: 100;
	pointer-events: none;
}
#video_on {
	opacity: 0;
}
#buffered_log {
	position: absolute;
	left: 10px;
	top: 34px;
	color: rgba(255,255,255,0.8);
	background: rgba(0,0,0,0.2);
	padding: 4px 7px;
	border-radius: 2px;
	font-size: 10px;
	z-index: 100;
	pointer-events: none;
}
#noise {
	position: absolute;
	left: 0;
	top: 0;
	border-radius: 8px;
	opacity: 0.5;
	pointer-events: none;
}
#infoModalBody {
	font-size: 12px;
	line-height: 16px;
}
.envSensors {
    float: right;
    margin-right: 5px;
}
.envSensor {
	float: right;
}
.envText {
	float: right;
	color: rgb(144, 113, 113);
}
#env01Value, #env02Value, #env03Value, #env04Value {
	font-family: 'AyatoNumA_eot', 'AyatoNumA_ttf';
	font-style: normal;
	font-weight: normal;
	color: #ffa020;
}
.uptimetitle, .uptimeunit, #uptime0Value, #uptime1Value, #uptime2Value, #uptime3Value, #uptime4Value {
	margin-left: 5px;
}
#video {
	border-radius: 8px;
}
</style>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!--<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-color/2.1.2/jquery.color.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bowser/1.7.0/bowser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/screenfull.js/3.2.2/screenfull.min.js"></script>
<script src="jquery.easypiechart.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/countup.js@1.9.1/dist/countUp.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
<script>
$(function() {
	if (Hls.isSupported()) {
		var video = document.getElementById('video');
		var hls = new Hls();
		hls.loadSource('http://dz.plala.jp:8087/stream/stream.m3u8');
		hls.attachMedia(video);
		/*hls.on(Hls.Events.FRAG_BUFFERED, function(event, data) {
			checkBuffer();
		});*/
		video.addEventListener('canplay', handleVideoEvent);
	}
	/*function timeRangesToString(r) {
		var log = [];
		for (var i = 0; i < r.length; i++) {
			log[0] = r.start(i);
			log[1] = r.end(i);
		}
		return log;
	}
	function checkBuffer() {
		var v = $('#video')[0];
		var vq = v.getVideoPlaybackQuality;
		var r = v.buffered;
		if (r) {
			var buffered = timeRangesToString(v.buffered);
			var seekable = timeRangesToString(v.seekable);
			var played = timeRangesToString(v.played);
			v01Update.update(v.duration);
			v02sUpdate.update(buffered[0]);
			v02eUpdate.update(buffered[1]);
			v03sUpdate.update(seekable[0]);
			v03eUpdate.update(seekable[1]);
			v04sUpdate.update(played[0]);
			v04eUpdate.update(played[1]);
			if(vq && typeof(vq) === typeof(Function)) {
				v05Update.update(v.getVideoPlaybackQuality().droppedVideoFrames);
				v06Update.update(v.getVideoPlaybackQuality().corruptedVideoFrames);
			} else if(v.webkitDroppedFrameCount) {
				v05Update.update(v.webkitDroppedFrameCount);
			}
		}
	}*/
	function handleVideoEvent() {
		$("#noise").remove();
		$("#video_off").css("opacity", 0);
		$("#video_on").css("opacity", 1.0);
		$('#video')[0].play();
	}
	$.fn.modal.prototype.constructor.Constructor.DEFAULTS.backdrop = 'static';
	$.fn.modal.prototype.constructor.Constructor.DEFAULTS.keyboard =  false;
	$('#infoModal').on('show.bs.modal', function () {
		$('#videoModal').modal('hide');
	})
	$('#videoModal').on('show.bs.modal', function () {
		$('#infoModal').modal('hide');
	})
	if(window.location.href.indexOf('#videoModal') != -1) {
		$('#videoModal').modal('show');
	}
	if(window.location.href.indexOf('#infoModal') != -1) {
		$('#infoModal').modal('show');
	}
	var updateValue = [];
	var uptimeTime = [];
	var gaugeList = [
		{title:	'CPU',			max:	100,	from:	80,		to:	100},
		{title:	'TEMP',			max:	85,		from:	70,		to:	85},
		{title:	'Free RAM',		max:	1024,	from:	0,		to:	64},
		{title:	'IPv4 IN',		max:	100000,	from:	80000,	to:	100000},
		{title:	'IPv4 OUT',		max:	100000,	from:	80000,	to:	100000},
		{title:	'Used DISK',	max:	8,		from:	6,		to:	8},
		{title:	'Disk READ',	max:	100,	from:	80,		to:	100},
		{title:	'Disk WRITE',	max:	100,	from:	80,		to:	100},
		{title:	'SWAP',			max:	100,	from:	10,		to:	100},
		{title:	'CPU',			max:	100,	from:	80,		to:	100},
		{title:	'TEMP',			max:	85,		from:	70,		to:	85},
		{title:	'Free RAM',		max:	1024,	from:	0,		to:	64},
		{title:	'IPv4 IN',		max:	100000,	from:	80000,	to:	100000},
		{title:	'IPv4 OUT',		max:	100000,	from:	80000,	to:	100000},
		{title:	'Used DISK',	max:	8,		from:	6,		to:	8},
		{title:	'Disk READ',	max:	100,	from:	80,		to:	100},
		{title:	'Disk WRITE',	max:	100,	from:	80,		to:	100},
		{title:	'SWAP',			max:	100,	from:	10,		to:	100},
		{title:	'CPU',			max:	100,	from:	80,		to:	100},
		{title:	'TEMP',			max:	85,		from:	70,		to:	85},
		{title:	'Free RAM',		max:	1024,	from:	0,		to:	64},
		{title:	'IPv4 IN',		max:	100000,	from:	80000,	to:	100000},
		{title:	'IPv4 OUT',		max:	100000,	from:	80000,	to:	100000},
		{title:	'Used DISK',	max:	8,		from:	6,		to:	8},
		{title:	'Disk READ',	max:	100,	from:	80,		to:	100},
		{title:	'Disk WRITE',	max:	100,	from:	80,		to:	100},
		{title:	'SWAP',			max:	100,	from:	10,		to:	100},
		{title:	'CPU',			max:	100,	from:	80,		to:	100},
		{title:	'TEMP',			max:	85,		from:	70,		to:	85},
		{title:	'Free RAM',		max:	512,	from:	0,		to:	64},
		{title:	'IPv4 IN',		max:	100000,	from:	80000,	to:	100000},
		{title:	'IPv4 OUT',		max:	100000,	from:	80000,	to:	100000},
		{title:	'Used DISK',	max:	8,		from:	6,		to:	8},
		{title:	'Disk READ',	max:	100,	from:	80,		to:	100},
		{title:	'Disk WRITE',	max:	100,	from:	80,		to:	100},
		{title:	'SWAP',			max:	100,	from:	10,		to:	100},
		{title:	'CPU',			max:	100,	from:	80,		to:	100},
		{title:	'TEMP',			max:	85,		from:	70,		to:	85},
		{title:	'Free RAM',		max:	1024,	from:	0,		to:	64},
		{title:	'IPv4 IN',		max:	100000,	from:	80000,	to:	100000},
		{title:	'IPv4 OUT',		max:	100000,	from:	80000,	to:	100000},
		{title:	'Used DISK',	max:	8,		from:	6,		to:	8},
		{title:	'Disk READ',	max:	100,	from:	80,		to:	100},
		{title:	'Disk WRITE',	max:	100,	from:	80,		to:	100},
		{title:	'SWAP',			max:	100,	from:	10,		to:	100}
	];
	var options = {
		useEasing: false,
		useGrouping: false,
		separator: '',
		decimal: '.',
	};
	var env01Update = new CountUp('env01Value', 0, 0, 2, 1, options);
	var env02Update = new CountUp('env02Value', 0, 0, 2, 1, options);
	var env03Update = new CountUp('env03Value', 0, 0, 2, 1, options);
	var env04Update = new CountUp('env04Value', 0, 0, 2, 1, options);
	var uptime0Update = new CountUp('uptime0Value', 0, 0, 2, 1, options);
	var uptime1Update = new CountUp('uptime1Value', 0, 0, 2, 1, options);
	var uptime2Update = new CountUp('uptime2Value', 0, 0, 2, 1, options);
	var uptime3Update = new CountUp('uptime3Value', 0, 0, 2, 1, options);
	var uptime4Update = new CountUp('uptime4Value', 0, 0, 2, 1, options);
	var v01Update = new CountUp('v01', 0, 0, 3, 0, options);
	var v02sUpdate = new CountUp('v02s', 0, 0, 3, 0, options);
	var v02eUpdate = new CountUp('v02e', 0, 0, 3, 0, options);
	var v03sUpdate = new CountUp('v03s', 0, 0, 3, 0, options);
	var v03eUpdate = new CountUp('v03e', 0, 0, 3, 0, options);
	var v04sUpdate = new CountUp('v04s', 0, 0, 3, 0, options);
	var v04eUpdate = new CountUp('v04e', 0, 0, 3, 0, options);
	var v05Update = new CountUp('v05', 0, 0, 0, 0, options);
	var v06Update = new CountUp('v06', 0, 0, 0, 0, options);
	
	var testTimer;
	function startTimer() {
		testTimer = setInterval(function() {
			$.ajax({
				url: 'http://dz.plala.jp:8081/api/v1/allmetrics?format=json',
				type: 'GET',
				cache: false,
				dataType: 'json',
				timeout: 4000
			}).done(function(obj) {
				updateValue[0] = 100 - obj["system.cpu"]["dimensions"]["idle"]["value"];
				updateValue[1] = obj["sensors.temp_thermal_zone0_thermal_thermal_zone0"]["dimensions"]["sys_devices_virtual_thermal_thermal_zone0_temp"]["value"];
				updateValue[2] = obj["system.ram"]["dimensions"]["free"]["value"];
				updateValue[3] = obj["system.ipv4"]["dimensions"]["InOctets"]["value"];
				updateValue[4] = Math.abs(obj["system.ipv4"]["dimensions"]["OutOctets"]["value"]);
				updateValue[5] = obj["disk_space._"]["dimensions"]["used"]["value"];
				updateValue[6] = obj["system.io"]["dimensions"]["in"]["value"];
				updateValue[7] = Math.abs(obj["system.io"]["dimensions"]["out"]["value"]);
				updateValue[8] = obj["system.swap"]["dimensions"]["used"]["value"];
				updateValue[45] = obj["EnvSensors.temperature"]["dimensions"]["temp"]["value"].toFixed(2);
				updateValue[46] = obj["EnvSensors.humidity"]["dimensions"]["hum"]["value"].toFixed(2);
				updateValue[47] = obj["EnvSensors.pressure"]["dimensions"]["press"]["value"].toFixed(2);
				updateValue[48] = obj["EnvSensors.lux"]["dimensions"]["lux"]["value"].toFixed(2);
				uptimeTime[0] = obj["system.uptime"]["dimensions"]["uptime"]["value"] / 86400;
				$('#gauge0').data('easyPieChart').update(updateValue[0]);
				$('#gauge1').data('easyPieChart').update(updateValue[1]);
				$('#gauge2').data('easyPieChart').update(updateValue[2]);
				$('#gauge3').data('easyPieChart').update(updateValue[3]);
				$('#gauge4').data('easyPieChart').update(updateValue[4]);
				$('#gauge5').data('easyPieChart').update(updateValue[5]);
				$('#gauge6').data('easyPieChart').update(updateValue[6]);
				$('#gauge7').data('easyPieChart').update(updateValue[7]);
				$('#gauge8').data('easyPieChart').update(updateValue[8]);
				for (var i = 0; i < 9; i++) {
					if ((i == 6 || i == 7) && updateValue[i] > gaugeList[i].from) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else if (updateValue[i] > gaugeList[i].from && updateValue[i] <= gaugeList[i].to) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else {
						$('#gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': '#907171'
						}, 600);
						$('#gauge' + i + ' .label').animate({
							'color': '#ffa020'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
					}
				}
				uptime0Update.update(uptimeTime[0]);
				env01Update.update(updateValue[45]);
				env02Update.update(updateValue[46]);
				env03Update.update(updateValue[47]);
				env04Update.update(updateValue[48]);
			}).fail(function() {
				for (var i = 0; i < 9; i++) {
					$('#gauge' + i + ' .label').animate({
						'color': '#907171'
					}, 600);
				}
			});
			$.ajax({
				url: 'http://dz.plala.jp:8081/host/seti/api/v1/allmetrics?format=json',
				type: 'GET',
				cache: false,
				dataType: 'json',
				timeout: 4000
			}).done(function(obj) {
				updateValue[9] = 100 - obj["system.cpu"]["dimensions"]["idle"]["value"];
				updateValue[10] = obj["sensors.temp_thermal_zone0_thermal_thermal_zone0"]["dimensions"]["sys_devices_virtual_thermal_thermal_zone0_temp"]["value"];
				updateValue[11] = obj["system.ram"]["dimensions"]["free"]["value"];
				updateValue[12] = obj["system.ipv4"]["dimensions"]["InOctets"]["value"];
				updateValue[13] = Math.abs(obj["system.ipv4"]["dimensions"]["OutOctets"]["value"]);
				updateValue[14] = obj["disk_space._"]["dimensions"]["used"]["value"];
				updateValue[15] = obj["system.io"]["dimensions"]["in"]["value"];
				updateValue[16] = Math.abs(obj["system.io"]["dimensions"]["out"]["value"]);
				updateValue[17] = obj["system.swap"]["dimensions"]["used"]["value"];
				uptimeTime[1] = obj["system.uptime"]["dimensions"]["uptime"]["value"] / 86400;
				$('#gauge9').data('easyPieChart').update(updateValue[9]);
				$('#gauge10').data('easyPieChart').update(updateValue[10]);
				$('#gauge11').data('easyPieChart').update(updateValue[11]);
				$('#gauge12').data('easyPieChart').update(updateValue[12]);
				$('#gauge13').data('easyPieChart').update(updateValue[13]);
				$('#gauge14').data('easyPieChart').update(updateValue[14]);
				$('#gauge15').data('easyPieChart').update(updateValue[15]);
				$('#gauge16').data('easyPieChart').update(updateValue[16]);
				$('#gauge17').data('easyPieChart').update(updateValue[17]);
				for (var i = 9; i < 18; i++) {
					if ((i == 15 || i == 16) && updateValue[i] > gaugeList[i].from) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else if (updateValue[i] > gaugeList[i].from && updateValue[i] <= gaugeList[i].to) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else {
						$('#gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': '#907171'
						}, 600);
						$('#gauge' + i + ' .label').animate({
							'color': '#ffa020'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
					}
				}
				uptime1Update.update(uptimeTime[1]);
			}).fail(function() {
				for (var i = 9; i < 18; i++) {
					$('#gauge' + i + ' .label').animate({
						'color': '#907171'
					}, 600);
				}
			});
			$.ajax({
				url: 'http://dz.plala.jp:8081/host/fr24/api/v1/allmetrics?format=json',
				type: 'GET',
				cache: false,
				dataType: 'json',
				timeout: 4000
			}).done(function(obj) {
				updateValue[18] = 100 - obj["system.cpu"]["dimensions"]["idle"]["value"];
				updateValue[19] = obj["sensors.temp_thermal_zone0_thermal_thermal_zone0"]["dimensions"]["sys_devices_virtual_thermal_thermal_zone0_temp"]["value"];
				updateValue[20] = obj["system.ram"]["dimensions"]["free"]["value"];
				updateValue[21] = obj["system.ipv4"]["dimensions"]["InOctets"]["value"];
				updateValue[22] = Math.abs(obj["system.ipv4"]["dimensions"]["OutOctets"]["value"]);
				updateValue[23] = obj["disk_space._"]["dimensions"]["used"]["value"];
				updateValue[24] = obj["system.io"]["dimensions"]["in"]["value"];
				updateValue[25] = Math.abs(obj["system.io"]["dimensions"]["out"]["value"]);
				updateValue[26] = obj["system.swap"]["dimensions"]["used"]["value"];
				uptimeTime[2] = obj["system.uptime"]["dimensions"]["uptime"]["value"] / 86400;
				$('#gauge18').data('easyPieChart').update(updateValue[18]);
				$('#gauge19').data('easyPieChart').update(updateValue[19]);
				$('#gauge20').data('easyPieChart').update(updateValue[20]);
				$('#gauge21').data('easyPieChart').update(updateValue[21]);
				$('#gauge22').data('easyPieChart').update(updateValue[22]);
				$('#gauge23').data('easyPieChart').update(updateValue[23]);
				$('#gauge24').data('easyPieChart').update(updateValue[24]);
				$('#gauge25').data('easyPieChart').update(updateValue[25]);
				$('#gauge26').data('easyPieChart').update(updateValue[26]);
				for (var i = 18; i < 27; i++) {
					if ((i == 24 || i == 25) && updateValue[i] > gaugeList[i].from) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else if (updateValue[i] > gaugeList[i].from && updateValue[i] <= gaugeList[i].to) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else {
						$('#gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': '#907171'
						}, 600);
						$('#gauge' + i + ' .label').animate({
							'color': '#ffa020'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
					}
				}
				uptime2Update.update(uptimeTime[2]);
			}).fail(function() {
				for (var i = 18; i < 27; i++) {
					$('#gauge' + i + ' .label').animate({
						'color': '#907171'
					}, 600);
				}
			});
			$.ajax({
				url: 'http://dz.plala.jp:8081/host/livebot3/api/v1/allmetrics?format=json',
				type: 'GET',
				cache: false,
				dataType: 'json',
				timeout: 4000
			}).done(function(obj) {
				updateValue[27] = 100 - obj["system.cpu"]["dimensions"]["idle"]["value"];
				updateValue[28] = obj["sensors.temp_thermal_zone0_thermal_thermal_zone0"]["dimensions"]["sys_devices_virtual_thermal_thermal_zone0_temp"]["value"];
				updateValue[29] = obj["system.ram"]["dimensions"]["free"]["value"];
				updateValue[30] = obj["system.ipv4"]["dimensions"]["InOctets"]["value"];
				updateValue[31] = Math.abs(obj["system.ipv4"]["dimensions"]["OutOctets"]["value"]);
				updateValue[32] = obj["disk_space._"]["dimensions"]["used"]["value"];
				updateValue[33] = obj["system.io"]["dimensions"]["in"]["value"];
				updateValue[34] = Math.abs(obj["system.io"]["dimensions"]["out"]["value"]);
				updateValue[35] = obj["system.swap"]["dimensions"]["used"]["value"];
				uptimeTime[3] = obj["system.uptime"]["dimensions"]["uptime"]["value"] / 86400;
				$('#gauge27').data('easyPieChart').update(updateValue[27]);
				$('#gauge28').data('easyPieChart').update(updateValue[28]);
				$('#gauge29').data('easyPieChart').update(updateValue[29]);
				$('#gauge30').data('easyPieChart').update(updateValue[30]);
				$('#gauge31').data('easyPieChart').update(updateValue[31]);
				$('#gauge32').data('easyPieChart').update(updateValue[32]);
				$('#gauge33').data('easyPieChart').update(updateValue[33]);
				$('#gauge34').data('easyPieChart').update(updateValue[34]);
				$('#gauge35').data('easyPieChart').update(updateValue[35]);
				for (var i = 27; i < 36; i++) {
					if ((i == 33 || i == 34) && updateValue[i] > gaugeList[i].from) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else if (updateValue[i] > gaugeList[i].from && updateValue[i] <= gaugeList[i].to) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else {
						$('#gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': '#907171'
						}, 600);
						$('#gauge' + i + ' .label').animate({
							'color': '#ffa020'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
					}
				}
				uptime3Update.update(uptimeTime[3]);
			}).fail(function() {
				for (var i = 27; i < 36; i++) {
					$('#gauge' + i + ' .label').animate({
						'color': '#907171'
					}, 600);
				}
			});
			$.ajax({
				url: 'http://dz.plala.jp:8081/host/flir/api/v1/allmetrics?format=json',
				type: 'GET',
				cache: false,
				dataType: 'json',
				timeout: 4000
			}).done(function(obj) {
				updateValue[36] = 100 - obj["system.cpu"]["dimensions"]["idle"]["value"];
				updateValue[37] = obj["sensors.temp_thermal_zone0_thermal_thermal_zone0"]["dimensions"]["sys_devices_virtual_thermal_thermal_zone0_temp"]["value"];
				updateValue[38] = obj["system.ram"]["dimensions"]["free"]["value"];
				updateValue[39] = obj["system.ipv4"]["dimensions"]["InOctets"]["value"];
				updateValue[40] = Math.abs(obj["system.ipv4"]["dimensions"]["OutOctets"]["value"]);
				updateValue[41] = obj["disk_space._"]["dimensions"]["used"]["value"];
				updateValue[42] = obj["system.io"]["dimensions"]["in"]["value"];
				updateValue[43] = Math.abs(obj["system.io"]["dimensions"]["out"]["value"]);
				updateValue[44] = obj["system.swap"]["dimensions"]["used"]["value"];
				uptimeTime[4] = obj["system.uptime"]["dimensions"]["uptime"]["value"] / 86400;
				$('#gauge36').data('easyPieChart').update(updateValue[36]);
				$('#gauge37').data('easyPieChart').update(updateValue[37]);
				$('#gauge38').data('easyPieChart').update(updateValue[38]);
				$('#gauge39').data('easyPieChart').update(updateValue[39]);
				$('#gauge40').data('easyPieChart').update(updateValue[40]);
				$('#gauge41').data('easyPieChart').update(updateValue[41]);
				$('#gauge42').data('easyPieChart').update(updateValue[42]);
				$('#gauge43').data('easyPieChart').update(updateValue[43]);
				$('#gauge44').data('easyPieChart').update(updateValue[44]);
				for (var i = 36; i < 45; i++) {
					if ((i == 42 || i == 43) && updateValue[i] > gaugeList[i].from) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else if (updateValue[i] > gaugeList[i].from && updateValue[i] <= gaugeList[i].to) {
						$('#gauge' + i + ' .label, #gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': 'red'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0.5'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = 'red';
					} else {
						$('#gauge' + i + ' .title, #gauge' + i + ' .units').animate({
							'color': '#907171'
						}, 600);
						$('#gauge' + i + ' .label').animate({
							'color': '#ffa020'
						}, 600);
						$('#gauge' + i + ' .alert').animate({
							'opacity': '0'
						}, 600);
						$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
					}
				}
				uptime4Update.update(uptimeTime[4]);
			}).fail(function() {
				for (var i = 36; i < 45; i++) {
					$('#gauge' + i + ' .label').animate({
						'color': '#907171'
					}, 600);
				}
			});
			if (bowser.mobile || bowser.tablet) {
				stopTimer();
			} else {
				//stopTimer();
			}
		}, 1000);
	};
	function stopTimer() {
		clearInterval(testTimer);
	};
	// Page Visibility API
	// https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API
	// Set the name of the hidden property and the change event for visibility
	var hidden, visibilityChange;
	if (typeof document.hidden !== "undefined") {
		hidden = "hidden";
		visibilityChange = "visibilitychange";
	} else if (typeof document.msHidden !== "undefined") {
		hidden = "msHidden";
		visibilityChange = "msvisibilitychange";
	} else if (typeof document.webkitHidden !== "undefined") {
		hidden = "webkitHidden";
		visibilityChange = "webkitvisibilitychange";
	};
	if (typeof document.addEventListener === "undefined" || typeof document[hidden] === "undefined") {
		console.log("This demo requires a browser, such as Google Chrome or Firefox, that supports the Page Visibility API.");
	} else {
		document.addEventListener(visibilityChange, handleVisibilityChange, false);
	};
	function handleVisibilityChange() {
		if (document[hidden]) {
			stopTimer();
		} else {
			startTimer();
		}
		$('.title, .units').css('color', '#907171');
		$('.label').css('color', '#ffa020');
		$('.alert').css('opacity', '0');
		for (var i = 0; i < gaugeList.length; i++) {
			$('#gauge' + i).data('easyPieChart').update(0);
			$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
		}
		uptime0Update.update(0);
		uptime1Update.update(0);
		uptime2Update.update(0);
		uptime3Update.update(0);
		uptime4Update.update(0);
		env01Update.update(0);
		env02Update.update(0);
		env03Update.update(0);
		env04Update.update(0);
	};
	var mobilrFirstFlag = true;
	function resize() {
		var windowWidth = $(window).innerWidth();
		var windowHeight = $(window).innerHeight();
		$("#infoModal").css({'top': ((windowHeight - 100) / 2) - 30, 'left': ((windowWidth - 550) / 2)});
		$("#videoModal").css({'top': ((windowHeight - 240) / 2) - 30, 'left': ((windowWidth - 320) / 2)});
		var split;
		var regulation;
		if (bowser.mobile) {
			if (windowWidth < windowHeight) {
				split = 3;
				regulation = 0;
			} else {
				split = 9;
				regulation = 18;
			}
		} else if (bowser.tablet) {
			if (windowWidth < windowHeight) {
				split = 5;
				regulation = 0;
			} else {
				split = 9;
				regulation = 18;
			}
		} else {
			split = 9;
			regulation = 18;
		}
		$(".wrapper-container, .navbar-container").css("width", $(window).innerWidth() * 0.85);
		var conatinerWidth = $(".wrapper-container").width();
		$(".gauge-container, .gauge, canvas").css({
			"width": Math.floor(105 * conatinerWidth / split / 105),
			"height": Math.floor(105 * conatinerWidth / split / 105)
		});
		if (mobilrFirstFlag) {
			$('.title, .units').css('color', '#907171');
			$('.label').css('color', '#ffa020');
			$('.alert').css('opacity', '0');
			clearTimeout(clearSet);
			var clearSet = setTimeout(function() {
				for (var i = 0; i < gaugeList.length; i++) {
					$('#gauge' + i).removeData('easyPieChart').find('canvas').remove();
					$('#gauge' + i).easyPieChart({
						size: Math.floor(105 * conatinerWidth / split / 105),
						maxValue: gaugeList[i].max,
						barColor: '#ffa020',
						trackColor: '#222',
						scaleColor: 'rgba(0,0,0,0)',
						scaleLength: Math.floor(3.5 * conatinerWidth / split / 105),
						lineWidth: Math.floor(3.5 * conatinerWidth / split / 105),
						rotate: 270,
						animate: ({
							duration: 1000,
							enabled: true
						}),
						onStep: function(from, to, currentValue) {
							$(this.el).find('.label').text(currentValue.toFixed(2));
						}
					});
					$('#gauge' + i).data('easyPieChart').update(0);
					$('#gauge' + i).data('easyPieChart').options.barColor = '#ffa020';
				};
				uptime0Update.update(0);
				uptime1Update.update(0);
				uptime2Update.update(0);
				uptime3Update.update(0);
				uptime4Update.update(0);
				env01Update.update(0);
				env02Update.update(0);
				env03Update.update(0);
				env04Update.update(0);
			}, 100);
		}
		if (bowser.mobile || bowser.tablet) {
			mobilrFirstFlag = false;
		} else {
			mobilrFirstFlag = true;
		}
		$(".envSensor").css({
			"margin-right": Math.floor(10 * conatinerWidth / split / 105)
		});
		$("#env01Value, #env02Value, #env03Value, #env04Value").css({
			"font-size": Math.floor(20 * conatinerWidth / split / 105)
		});
		$(".sensorUnit").css({
			"font-size": Math.floor(11 * conatinerWidth / split / 105)
		});
		$(".hard, .hardSub").css("font-size", Math.floor(11 * conatinerWidth / split / 105));
		$(".title").css({
			"font-size": Math.floor(11 * conatinerWidth / split / 105),
			"top": Math.floor(26 * conatinerWidth / split / 105)
		});
		$(".label").css({
			"font-size": Math.floor(20 * conatinerWidth / split / 105),
			"top": Math.floor(40 * conatinerWidth / split / 105)
		});
		$(".units").css({
			"font-size": Math.floor(11 * conatinerWidth / split / 105),
			"top": Math.floor(66 * conatinerWidth / split / 105)
		});
		$(".alert, .back").css({
			"left": Math.floor(6 * conatinerWidth / split / 105),
			"top": Math.floor(6 * conatinerWidth / split / 105),
			"width": Math.floor(94 * conatinerWidth / split / 105),
			"height": Math.floor(94 * conatinerWidth / split / 105)
		});
	};
	$(window).on('resize', function() {
		resize();
	});
	$("#fullscreen").on('click', function() {
		if (screenfull.isFullscreen) {
			screenfull.exit();
		} else {
			screenfull.request($('html')[0]);
		}
	});
	$(".href").on('click', function() {
		if (screenfull.isFullscreen) {
			screenfull.exit();
		}
		if ($(this).attr('id') == "wiki") {
			window.open("http://dz.plala.jp/wiki/index.php/RaspberryPi%E3%81%A7%E3%83%AA%E3%82%BD%E3%83%BC%E3%82%B9%E3%81%AE%E5%8F%AF%E8%A6%96%E5%8C%96(NetData%E7%89%88)", "_blank");
		} else if ($(this).attr('id') == "netdata") {
			window.open("https://my-netdata.io/", "_blank");
		} else if ($(this).attr('id') == "nginx") {
			window.open("https://nginx.org/", "_blank");
		} else if ($(this).attr('id') == "grafana") {
			window.open("https://grafana.com/", "_blank");
		}
	});
	function init() {
		if (bowser.mobile || bowser.tablet) {
			$("#fullscreen, #grafanaicon, #netdataicon, #tvicon, #infoicon").remove();
			$(".nav").remove();
			$(".envSensors").remove();
			$(".uptimetitle, .uptimeunit").remove();
			$("#uptime0Value, #uptime1Value, #uptime2Value, #uptime3Value, #uptime4Value").remove();
		} else {
			$(".dummy").css("height", 0);
		}
		if (bowser.chrome) {
			$("#video").css("-webkit-mask-image", "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC)");
		}
		startTimer();
		resize();
		setTimeout(function() {
			$(".wrapper").css("opacity", "1.0");
		}, 100);
	};
	init();
});
</script>
</head>
<body>
<div id="smoke"></div>
<div class="wrapper">
	<div class="wrapper-inner">
		<div class="wrapper-container">
			<div class="dummy"></div>
			<div class="envSensors">
				<div class="envSensor">
					<div class="envText"><span id="env04Value"></span><span class="sensorUnit"> lx</span></div>
				</div>
				<div class="envSensor">
					<div class="envText"><span id="env03Value"></span><span class="sensorUnit"> hPa</span></div>
				</div>
				<div class="envSensor">
					<div class="envText"><span id="env02Value"></span><span class="sensorUnit"> %</span></div>
				</div>
				<div class="envSensor">
					<div class="envText"><span id="env01Value"></span><span class="sensorUnit"> °C</span></div>
				</div>
			</div>
			<div class="clear"></div>
			<div class="hard">Main Control<span class="uptimetitle">- Uptime</span><span id="uptime0Value"></span><span class="uptimeunit">Day -</span><span class="hardSub">Raspberry Pi 2 Model B v1.1 a01041 (Sony, UK)</span></div>
			<div class="clear"></div>
			<div class="gauge-container">
				<div id="gauge0" class="gauge"> <span class="title">CPU</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge1" class="gauge"> <span class="title">TEMP</span> <span class="label"></span> <span class="units">°C</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge2" class="gauge"> <span class="title">Free RAM</span> <span class="label"></span> <span class="units">MB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge3" class="gauge"> <span class="title">IPv4 IN</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge4" class="gauge"> <span class="title">IPv4 OUT</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge5" class="gauge"> <span class="title">Used DISK</span> <span class="label"></span> <span class="units">GB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge6" class="gauge"> <span class="title">Disk READ</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge7" class="gauge"> <span class="title">Disk WRITE</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge8" class="gauge"> <span class="title">SWAP</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="clear"></div>
			<div class="hard">SETI<span class="uptimetitle">- Uptime</span><span id="uptime1Value"></span><span class="uptimeunit">Day -</span><span class="hardSub">Raspberry Pi 2 Model B v1.1 a01041 (Sony, UK)</span></div>
			<div class="clear"></div>
			<div class="gauge-container">
				<div id="gauge9" class="gauge"> <span class="title">CPU</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge10" class="gauge"> <span class="title">TEMP</span> <span class="label"></span> <span class="units">°C</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge11" class="gauge"> <span class="title">Free RAM</span> <span class="label"></span> <span class="units">MB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge12" class="gauge"> <span class="title">IPv4 IN</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge13" class="gauge"> <span class="title">IPv4 OUT</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge14" class="gauge"> <span class="title">Used DISK</span> <span class="label"></span> <span class="units">GB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge15" class="gauge"> <span class="title">Disk READ</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge16" class="gauge"> <span class="title">Disk WRITE</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge17" class="gauge"> <span class="title">SWAP</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="clear"></div>
			<div class="hard">ADS-B Multi Feeder<span class="uptimetitle">- Uptime</span><span id="uptime2Value"></span><span class="uptimeunit">Day -</span><span class="hardSub">Raspberry Pi 3 Model B a02082 (Sony, UK)</span></div>
			<div class="clear"></div>
			<div class="gauge-container">
				<div id="gauge18" class="gauge"> <span class="title">CPU</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge19" class="gauge"> <span class="title">TEMP</span> <span class="label"></span> <span class="units">°C</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge20" class="gauge"> <span class="title">Free RAM</span> <span class="label"></span> <span class="units">MB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge21" class="gauge"> <span class="title">IPv4 IN</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge22" class="gauge"> <span class="title">IPv4 OUT</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge23" class="gauge"> <span class="title">Used DISK</span> <span class="label"></span> <span class="units">GB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge24" class="gauge"> <span class="title">Disk READ</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge25" class="gauge"> <span class="title">Disk WRITE</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge26" class="gauge"> <span class="title">SWAP</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="clear"></div>
			<div class="hard">LIVEBOT3<span class="uptimetitle">- Uptime</span><span id="uptime3Value"></span><span class="uptimeunit">Day -</span><span class="hardSub">Raspberry Pi Zero v1.3 900093</span></div>
			<div class="clear"></div>
			<div class="gauge-container">
				<div id="gauge27" class="gauge"> <span class="title">CPU</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge28" class="gauge"> <span class="title">TEMP</span> <span class="label"></span> <span class="units">°C</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge29" class="gauge"> <span class="title">Free RAM</span> <span class="label"></span> <span class="units">MB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge30" class="gauge"> <span class="title">IPv4 IN</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge31" class="gauge"> <span class="title">IPv4 OUT</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge32" class="gauge"> <span class="title">Used DISK</span> <span class="label"></span> <span class="units">GB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge33" class="gauge"> <span class="title">Disk READ</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge34" class="gauge"> <span class="title">Disk WRITE</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge35" class="gauge"> <span class="title">SWAP</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="clear"></div>
			<div class="hard">FLiR Live Camera<span class="uptimetitle">- Uptime</span><span id="uptime4Value"></span><span class="uptimeunit">Day -</span><span class="hardSub">Raspberry Pi 3 Model B a02082 (Sony, UK)</span></div>
			<div class="clear"></div>
			<div class="gauge-container">
				<div id="gauge36" class="gauge"> <span class="title">CPU</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge37" class="gauge"> <span class="title">TEMP</span> <span class="label"></span> <span class="units">°C</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge38" class="gauge"> <span class="title">Free RAM</span> <span class="label"></span> <span class="units">MB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge39" class="gauge"> <span class="title">IPv4 IN</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge40" class="gauge"> <span class="title">IPv4 OUT</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge41" class="gauge"> <span class="title">Used DISK</span> <span class="label"></span> <span class="units">GB</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge42" class="gauge"> <span class="title">Disk READ</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge43" class="gauge"> <span class="title">Disk WRITE</span> <span class="label"></span> <span class="units">Kbps</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
			<div class="gauge-container">
				<div id="gauge44" class="gauge"> <span class="title">SWAP</span> <span class="label"></span> <span class="units">%</span> <span class="alert"></span> <span class="back"></span></div>
			</div>
		</div>
	</div>
</div>
<img id="fullscreen" src="images/fullscreen.png">
<a href="http://dz.plala.jp:3000" target="_blank"><img id="grafanaicon" src="images/grafana.png"></a>
<a href="http://dz.plala.jp:8081" target="_blank"><img id="netdataicon" src="images/netdata.png"></a>
<span data-toggle="modal" data-target="#videoModal"><img id="tvicon" src="images/television.png"></span>
<span data-toggle="modal" data-target="#infoModal"><img id="infoicon" src="images/info.png"></span>

<div class="modal fade" id="infoModal" role="dialog" aria-labelledby="infoModalLabel">
	<div class="modal-dialog" role="document">
		<div class="modal-content">
			<img src="images/close.png" type="button" class="close" data-dismiss="modal" aria-label="Close">
			<div class="modal-body" id="infoModalBody">
				<div> <span class="glyphicon glyphicon-th-large" aria-hidden="true" style="margin-right:2px;margin-bottom:6px;"></span>IoT MONITOR <span id ="wiki" class="href">wiki</span><br />
					IoT機器を<span id ="netdata" class="href">NetData</span>で監視、<span id ="nginx" class="href">nginx</span>で集約ビジュアル化、<span id ="grafana" class="href">Grafana</span>で記録管理解析するシステム<br />
					Code licensed MIT, docs CC BY 4.0.<br />
					Copyright © 2017 shogooda All rights reserved.
				</div>
			</div>
		</div>
	</div>
</div>
<div class="modal fade" id="videoModal" role="dialog" aria-labelledby="infoModalLabel">
	<div class="modal-dialog" role="document">
		<div class="modal-content">
			<img src="images/close.png" type="button" class="close" data-dismiss="modal" aria-label="Close">
			<img id="video_off" src="images/liveicon_off.png">
			<img id="video_on" src="images/liveicon_on.png">
			<!--<div id="buffered_log">
				<div>Duration: <span id="v01"></span></div>
				<div>Buffered: <span id="v02s"></span>, <span id="v02e"></span></div>
				<div>Seekable: <span id="v03s"></span>, <span id="v03e"></span></div>
				<div>Played: <span id="v04s"></span>, <span id="v04e"></span></div>
				<div>Dropped Frames: <span id="v05"></span></div>
				<div>Corrupted Frames: <span id="v06"></span></div>
			</div>-->
			<div class="modal-body" id="videoHandle">
				<video id="video" muted controls></video>
				<img id="noise" src="images/noise.gif">
			</div>
		</div>
	</div>
</div>
</body>
</html>

ファビコン

http://dz.plala.jp/wiki_data/favicons.zip

その他

http://dz.plala.jp/iot-monitor/jquery.easypiechart.js
fullscreen.png
info.png
grafana.png
netdata.png

ゲージのカスタマイズ

RaspberryPiでリソースの可視化(NetData版)付録参照

消費電力の設定

参考: Raspberry Pi 3 Model B の消費電力削減 - Rabbit Note

USB電源をOFF(VNCで操作すると接続が切れてしまいます。ご注意。)

$ sudo sh -c "echo 0 > /sys/devices/platform/soc/20980000.usb/buspower"
または
$ sudo sh -c "echo 0 > /sys/devices/platform/soc/3f980000.usb/buspower"
ONにする場合は0を1に

HDMI電源をOFF

$ sudo /opt/vc/bin/tvservice -o
ONにする場合
$ sudo /opt/vc/bin/tvservice -p

再起動

$ sudo reboot

メモリの節約

参考: Raspberry メモリ 節約 - Google

デーモンの停止

$ sudo apt-get install chkconfig
$ #sudo chkconfig dbus off
$ sudo chkconfig triggerhappy off
$ sudo chkconfig alsa-utils off
$ sudo chkconfig lightdm off
$ sudo chkconfig motd off
$ sudo chkconfig plymouth off

topコマンド見るとXorg(デスクトップ環境)がいちばんメモリを消費しています。停止してみます。
※この操作するとVNCが機能しないように見えます。復帰にはモニター、マウス、キーボード必要です。

Menu→設定→RaspberryPiの設定→システムタブ→ブート→CLIにチェック→再起動

Xorg(デスクトップ環境)復帰方法

電源OFF
モニター、マウス、キーボードを取り付け
電源ON
コマンドプロンプトの状態
$ sudo startx
デスクトップ環境起動
Menu→設定→RaspberryPiの設定→システムタブ→ブート→デスクトップにチェック→シャットダウン
モニター、マウス、キーボード取り外し
電源ON
VNCなどで接続

アップデート

参考: Installation · firehol/netdata Wiki · GitHub

$ cd ~
$ cd netdata
$ sudo ./netdata-updater.sh

このスクリプトを使用すると、最初にインストールしたのと同じオプションで更新できます。だそうです。

再起動

$ sudo reboot

参考