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

追加アプリ

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

$ bash <(curl -Ss https://my-netdata.io/kickstart.sh)

設定

$ sudo nano /etc/netdata/netdata.conf

変更

[global]
           history = 600
           memory mode = ram
           debug log = none
           error log = none
           access log = none
[web]
           enable gzip compression = no
[plugins]
           cgroups = no
           tc = no
           idlejitter = no

保存: Ctrl + o リターン
終了: Ctrl + x

温度センサ設定

$ sudo /etc/netdata/edit-config charts.d.conf

#コメント消去

sensors=force

保存: Ctrl + o リターン
終了: Ctrl + x

再起動

$ sudo service netdata restart

動作確認

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

環境センサの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の項目があれば動いています


複数台集約

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

参考: 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 /etc/netdata/edit-config stream.conf

[stream]の項目に入力(destinationはマスターの固定IPアドレス)

[stream]
enabled = yes
destination = 192.168.1.187:19999
api key = 11111111-2222-3333-4444-555555555555

保存: Ctrl + o リターン
終了: Ctrl + x

$ sudo nano /etc/netdata/netdata.conf

書き換え

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

保存: Ctrl + o リターン
終了: Ctrl + x

再起動

$ sudo service netdata restart

確認
マスターの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をインストールしてみます。

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

アップデート

メモ

$ cd /usr/src/netdata.git
$ sudo git pull
$ sudo ./netdata-installer.sh

再起動

$ sudo reboot

延命対策

nginx

logがRAMディスクの許容を超えるので無効に
設定

$ sudo nano /etc/nginx/nginx.conf

変更

#access_log /var/log/nginx/access.log;
#error_log /var/log/nginx/error.log;
access_log off;
error_log off;

再起動

$ sudo reboot

swap

無効化
Stretchの場合

$ sudo dphys-swapfile swapoff
$ sudo systemctl stop dphys-swapfile
$ sudo systemctl disable dphys-swapfile

fstab

設定

$ sudo nano /etc/fstab

nodiratime追記と末尾に追記
参考: fstab - ArchWiki atime オプション

PARTUUID=762cd6c9-02  /               ext4    defaults,noatime,nodiratime  0       1
tmpfs    /tmp                              tmpfs    defaults,noatime,nodiratime,mode=1777  0       0
tmpfs    /run/user/1000                    tmpfs    defaults,noatime,nodiratime,mode=1777  0       0
tmpfs    /home/pi/.cache/lxsession/LXDE-pi tmpfs    defaults,noatime,nodiratime,mode=1777  0       0
tmpfs    /var/lib/netdata                  tmpfs    defaults,noatime,nodiratime,mode=1777  0       0

保存: Ctrl + o リターン
終了: Ctrl + x

再起動

$ sudo reboot

確認

$ df -h

systemctl

確認

$ systemctl list-unit-files -t service|grep enabled

rsyslog停止

$ sudo systemctl stop rsyslog.service
$ sudo systemctl disable rsyslog.service
戻すなら
$ sudo systemctl enable rsyslog.service

bluetooth停止

$ sudo systemctl stop hciuart.service
$ sudo systemctl stop bluetooth.service
$ sudo systemctl disable hciuart.service
$ sudo systemctl disable bluetooth.service
戻すなら
$ sudo systemctl enable hciuart.service
$ sudo systemctl enable bluetooth.service

再起動

$ sudo reboot

確認

$ systemctl list-unit-files -t service
$ systemctl list-unit-files -t service|grep disabled

folder2ram

RAMディスク化

参考: GitHub - bobafetthotmail/folder2ram: mount those folders to ram without losing access to their counterpart on disk!

インストール

$ sudo wget -O /sbin/folder2ram https://raw.githubusercontent.com/bobafetthotmail/folder2ram/master/debian_package/sbin/folder2ram
$ sudo chmod +x /sbin/folder2ram
$ sudo folder2ram -configure
will now open the configuration file with your favourite text editor
write its name and press enter (nano, vim, gedit are the most common)
リターン
$ sudo nano /etc/folder2ram/folder2ram.conf

末尾に追記

tmpfs		/var/log
tmpfs		/var/tmp
tmpfs		/var/spool
tmpfs		/var/cache/samba

保存: Ctrl + o > リターン
終了: Ctrl + x

$ sudo folder2ram -mountall
$ sudo folder2ram -enablesystemd

再起動

$ sudo reboot

確認

$ df -h

journald

参考: man journald.conf の訳

$ sudo nano /etc/systemd/journald.conf

追記

Storage=none

保存: Ctrl + o > リターン
終了: Ctrl + x

再起動

$ sudo reboot

sysctl

Netdataでsoftnetの警告が必ず出る

過去10分間に、ksoftirqがsysctl net.core.netdev_budgetまたはnet.core.netdev_budget_usecsを使い果たし作業が残っている。これはパケットがドロップされる原因となる可能性があります。

参考: Red Hat Enterprise Linux Network Performance Tuning Guide
参考: Can't fix persistent 'netdev budget ran outs' with 45k alerts, need help #4624

設定

$ sudo nano /etc/sysctl.conf

末尾に追記

net.core.netdev_budget_usecs=20000

保存: Ctrl + o > リターン
終了: Ctrl + x

再起動

$ sudo reboot

更新履歴

  • 2017.08.27 書き直し
  • 2017.05.15 公開