日記 : 社会人2年目・とりあえず読んで欲しいお肉の話

久しぶりの記事となってしまいました。

時が経つのは早いもので,いつの間にか社会人生活も2年目に突入していました。 本当にいろいろな出来事があり,学ぶことや考えさせられることの多い1年間でした。 時には様々な方々に迷惑をおかけしてしまうこともありましたが,過去の人生の中で一番濃い時間だったのではないかと思います。

牛肉おいしい

閑話休題

先日,ちょっとした用事で普段自分では買わないような国産和牛のお弁当を食べる機会がありました。 久々に甘辛く味付けされたお肉を食べてみると非常に美味しく,翌日の夕飯は吉野家で牛カルビ丼を食べました。 先日食べた国産和牛とは比較に及びませんが,これもまた十分に美味しく満足出来るものでした。

帰宅する最中,ふと「お肉の質」ってなんだろうと思いました。

産地や等級など,お肉には様々な「階級付け」が存在します。それが表すところは生まれ育った産地であったり 飼料の種類であったり多種多様です。

しかし,両者は同じ「牛肉」であり,「牛肉」である以上「牛という動物の肉」であることには変わらないのです。 生前の牛たちは格付けされており,その評価基準は「人間が食べて美味しいものであるか」というものでした。

食べられる牛側からしてみれば,いくら高い等級がつけられようと全く嬉しくないでしょう。 この格付が人間基準の評価であり,人間がどう利益を享受できるのかでしか判断されていないものである以上当然ではあります。

しかし,「格付が当人の利益に結びつかない」という話は,別に人間社会においても何ら変わりないものだと思うのです。

社会的地位≠人としての幸福

一般的に,社会的地位が低くて損をすることは無いでしょう。この部分については「肉として格付けされる牛」とは異なっています。

ですが人としての本質的な部分を考えた時,社会的地位は何も手助けしてくれないどころか,むしろ阻害要因にすらなり得る部分があります。

仮にあなたが超一流のエンジニアであると考えてください。業界内であなたの名を知らない人はおらず,多くの人から尊敬されているとします。 あなたが何かを作れば誰かが必ず反応し,良くも悪くも常にフィードバックが得られます。あなたはそのフィードバックを元に試行錯誤をしつつ,更なる高みを目指していくことでしょう。

しかし,順調に良いサイクルが回り続ける保証はどこにもありません。大概にして良いサイクルは数年程度で崩れてしまいます。

先程の例で考えてみます。あなたは超一流のエンジニアで良いものを常に産み出し続けています。しかし,ある日突然スランプに陥ってしまいました。業界のトレンドについていけず,考え方の刷新も図れない,次第に周りに居た人達はどんどん離れてゆき,最終的に孤独が訪れます。

こうなる理由は簡単で,周りはあなた自身を評価していたのではなく,その能力を評価していたからです。人は往々にしてここで勘違いをしてしまい,評価を失った時に負のスパイラルに陥ってしまいます。

これ,本質的に「肉」として格付けされた牛と同じなのです。むしろ本人が「自己への評価」だと思いこんでしまっている分,真実を知ったときのダメージが大きく,質が悪いといえるかもしれません。

「本当の自分」を評価してくれる人を大切に

最終的に言いたいのはこれです。「超一流の誰からも尊敬されるようなエンジニアになってやる!」と考えるのは大事ですし,向上心を持つことは専門職をやっていく上で必要不可欠です。

ただ,「能力を抜きにした自分」を評価してくれる人・環境を大切にすることを忘れないでください。それが家族,友人,恋人など何であるかは別にどうだっていいと思います。

ただ一つ言えることは,いつか挫折し地位を失った時,あなたを支えてくれるのはその人達だけだろうということです。

そういう人が周りに居てくれるということは本当に幸せなことだと思います。

日記 : 代入拒否症候群とphpにおけるブロックスコープ問題

代入こわい

最近代入が嫌いになってきた。

代入を行うとそのスコープの変数が汚染されてしまう。 特にブロックスコープの無い言語であるphpにおいてはforeachの受け先変数すらも汚染の対象になってしまう。

例えばこんな感じに

<?php

$bongos = [
    'bongo' => 'ボンゴ',
    'conga' => 'コンガ',
    'djembe' => 'ジャンベ'
];
$filtered_bongos = []; // 欲しい物

// foreachを使って欲しい値のみ$filtered_bongosに追加していく
foreach ($bongos as $key => $value) {
    if ($key !== 'djembe') {
        $filtered_bongos[$key] = $value;
    }
}

var_dump($filtered_bongos);
var_dump($key ?? 'keyない');
var_dump($value ?? 'valueない');

/*
array(2) {
  ["bongo"]=>
  string(9) "ボンゴ"
  ["conga"]=>
  string(9) "コンガ"
}
string(6) "djembe"
string(12) "ジャンベ"
*/

ので,array_*系関数を使ってちょっとだけ関数型っぽく書いてみる。少しきれいでちょっとかっこいい。

<?php
$bongos = [
    'bongo' => 'ボンゴ',
    'conga' => 'コンガ',
    'djembe' => 'ジャンベ'
];
$filtered_bongos = array_filter(function ($key) {
    return ($key !== 'djembe');
}, $bongos, ARRAY_FILTER_USE_KEY);

var_dump($filtered_bongos);
/*
array(2) {
  ["bongo"]=>
  string(9) "ボンゴ"
  ["conga"]=>
  string(9) "コンガ"
}
*/

が,Closureを用いており,要素毎に関数呼出が発生する為速度的にはforeachより圧倒的に遅くなる。 array_*系の関数は便利できれいに書けるが,パフォーマンスを重視する時は使わない方が良い。(そもそもそんな用途でphpを使うなと言われたらそれまでだけど)

解決策

意外とある。まず最初に思いつくのはunsetを用いて変数を明示的に開放してしまう方法かと思う。

<?php

$bongos = [
    'bongo' => 'ボンゴ',
    'conga' => 'コンガ',
    'djembe' => 'ジャンベ'
];
$filtered_bongos = []; // 欲しい物

// foreachを使って欲しい値のみ$filtered_bongosに追加していく
foreach ($bongos as $key => $value) {
    if ($key !== 'djembe') {
        $filtered_bongos[$key] = $value;
    }
}
// 開放する
unset($key);
unset($value);

var_dump($filtered_bongos);
var_dump($key ?? 'keyない');
var_dump($value ?? 'valueない');
/*
array(2) {
  ["bongo"]=>
  string(9) "ボンゴ"
  ["conga"]=>
  string(9) "コンガ"
}
string(9) "keyない"
string(11) "valueない"
*/

が,これだとどうしても構文が冗長で汚らしくなってしまう。

ただでさえforeachで書くと見栄えが悪くなるので,流石にちょっと勘弁してほしい。 しかもこれだと開放を忘れる可能性もある。危険。

ので,次のようにして解決してみる。

<?php

$bongos = [
    'bongo' => 'ボンゴ',
    'conga' => 'コンガ',
    'djembe' => 'ジャンベ'
];
$filtered_bongos = []; // 欲しい物

// Closureに閉じ込める
$filter = function (array $bongos) {
    $filtered_bongos = [];
    foreach ($bongos as $key => $value) {
        if ($key !== 'djembe') {
            $filtered_bongos[$key] = $value;
        }
    }
    
    return $filtered_bongos;
};

$filtered_bongos = $filter($bongos);

var_dump($filtered_bongos);
var_dump($key ?? 'keyない');
var_dump($value ?? 'valueない');

/*
array(2) {
  ["bongo"]=>
  string(9) "ボンゴ"
  ["conga"]=>
  string(9) "コンガ"
}
string(9) "keyない"
string(11) "valueない"
*/

Closure使ってるしさっきのと何が違うんだよ,というところだけれど,単にClosureの中に手続きを閉じ込めているだけなのでarray_filterと違って要素毎に関数呼び出しが行われることはない。ので少しだけ速度面ではマシになる(はず)

でもやっぱり構文が長ったらしくてダルいのでよほどのことがなければarray_*系関数使っちゃうよね。仕方ないね。

雑記 : PHP_CodeSnifferとPHPCompatibility

自分の書いているphpのコードが特定のphpバージョンで正常に動作するか確認したい。

ということでPHP_CodeSniffer(squizlabs/PHP_CodeSniffer)とPHPCompatibility(wimg/PHPCompatibility)を使って解析する方法をQiitaに投げた。

php 7.0へのマイグレーション確認用には他にもsstale/php7ccとかもあるようだけど,どうなんだろうか。

雑記 : Laravelの嫌いなところ

Laravelは好きだけど

Laravelは今最もトレンドなphp言語向けWebアプリケーションフレームワークで,5.1 LTSのリリース時から使い続けています。

以前使っていたZend Framework 2よりはるかに直感的に扱え,まさに「作りたい物を作りたいところだけ」作れる,そんな理想の存在がLaravelでした。

が,使い続けていくうちにだんだんと嫌なところも見えてきます。今回はそんなLaravelの嫌なところをまとめてみました。

1. Facadeが嫌い

Laravelにはまるで静的メソッドのようにインスタンスの動的なメソッドを呼び出すことの出来るFacadeという便利な仕組みがあります。

これはFacadeと呼ばれる静的クラスが,php言語のマジックメソッドを用いてDIコンテナにアクセスし,取得したインスタンスの動的メソッドを実行するというものです。

確かにこの構造は便利で,場所を気にせず好きなところでロジックを呼び出せます。

しかしこの構造はとてもいびつであり,DIコンテナとコンストラクタ・メソッドインジェクションによって下げられた疎結合性を一気に密結合なものへと変えてしまいます。

また,Facadeを用いた処理の実行は毎回マジックメソッドを経由して行われる為,実行コストも高いものとなります。そもそも強力なコンストラクタ・メソッドインジェクションがあるLaravelにおいては,Facadeの使用は必要最小限,もしくは完全に撤廃してしまっても問題ないように思います。

幸いにも,Laravel 5.5 LTSの時点ではFacadeの使用は任意であり,作成したプロジェクトのいくつかのファイルを修正することでFacadeを用いずにアプリケーションを作ることも可能です。また,そういった手法を用いることを好んでいる方も居ます(私もその一人です)

2. ヘルパ関数が嫌い

1.のFacadeが嫌いとほぼ同じ理由です。が,これに関しては回避手段がありません。LaravelはDIコンテナに対しstringで値を登録していることが多く,そのような値を取得するには最悪でもServiceLocator アンチパターンを用いるしかなくなってしまいます。

例えば,プロジェクトのストレージパスを取得するstorage_path()ヘルパ関数の実装がどのようになっているのか見てみましょう。

<?php

// 省略
if (! function_exists('storage_path')) {
    /**
     * Get the path to the storage folder.
     *
     * @param  string  $path
     * @return string
     */
    function storage_path($path = '')
    {
        return app('path.storage').($path ? DIRECTORY_SEPARATOR.$path : $path);
    }
}
// 省略

まずはapp()ヘルパ関数に対し,path.storageという文字列を与えているのがわかります。

ではapp()ヘルパ関数の実装を見てみます。

<?php
// 省略
if (! function_exists('app')) {
    /**
     * Get the available container instance.
     *
     * @param  string  $abstract
     * @param  array   $parameters
     * @return mixed|\Illuminate\Foundation\Application
     */
    function app($abstract = null, array $parameters = [])
    {
        if (is_null($abstract)) {
            return Container::getInstance();
        }

        return Container::getInstance()->make($abstract, $parameters);
    }
}
// 省略

はい,そうなのです。path.storageという文字列を抽象として,パスという文字列を具象として登録しています。

文字列は紛れもない具象です。文字列を表す抽象は存在し得ず,またオブジェクトではない為,コンストラクタ・メソッドインジェクションのどちらも使うことが出来ません。

Laravelは多くの箇所でこのような文字列に対する具象登録を行っており,ServiceLocatorパターンを用いない限り登録された具象を取得することが出来ません。これは回避不可能です。

3. Contractsが嫌い

Laravelは具象と抽象を区別するためにContractsという名前空間を用いてインターフェイスを隔離しています。しかし全ての具象に対してContractsが存在するわけではなく,またContracts以下の名前空間の問題からasを用いた別名定義を用いなければ使えない状況が多発しています。

例えば,Controllerのメソッドインジェクションを用いてViewCacheインスタンスを取得しようとすると,以下のようになります。

<?php

namespace App\Http\Controllers;

use Illuminate\Contracts\View\Factory as ViewFactory;
use Illuminate\Contracts\Cache\Factory as CacheFactory;

class TestController extends Controller
{
    public function index(ViewFactory $view, CacheFactory $cache)
    {
        $view->make('welcome');
    }
}

4. Eloquentが嫌い

嫌いというか,非常に学習コストが高いです。ActiveRecordのようにも見えますがActiveRecordにもなりきれておらず,悪く言えば中途半端,良く言えばどうとでも使えるOR Mapperになっています。

というのも,Eloquentは前述のFacadeと親しい部分があり,それがデータベースを表すのか行を表すのかが非常に判別しにくくなっています。

具体的に言うとこんな感じになります。あまりにわかりにくいので変数名にinstanceと命名することでそれが何であるかを明確にせざるを得ませんでした。

それでもLaravelは何よりも現実的

確かに設計の面でいびつな部分も数多く存在するLaravelですが,現在存在するphp言語向けWebアプリケーションフレームワークの中では最も開発効率に優れたものであるということも間違いないであろうと思っています。

Facadeヘルパ関数はコードの品質を下げかねない諸刃の剣ですが,使い方を間違えさえしなければよほどのことにはなりません。仮に密結合なコードを書いてしまったとしても,LaravelのDIコンテナには後からそれを救う機能が備わっています。

結論としては,Laravelはやっぱり良いフレームワークだな,というところでした。

それでもphp 7.1が使いたかったんだ

という文章をQiitaに投げました。

qiita.com

PHPerの幸福はphp 7.1以降にあると信じています。

日記 : 「創作」と呼べるアプリケーションコーディングと設計技法について

はじめに

個人的に「創作」という言葉には強い思い入れがあります。

自分は生まれてからずっと「創作」されたもので心を動かされてきたし,何よりも今の人格を形成しているものが「創作」されたものであったと考えているからです。

なので,「創作」を行える人は非常に尊い存在であると感じており,また自分がそれに携われない,支援できないという部分において深く無力感を感じている部分でもあります。

しかし,嘆いているだけでは何にもなりません。仮に自分が「創作」に携われないとしても,それをエンジニアリングで支援することは出来るはずです。嘆く前に,まずは行動するべきなのです。

では具体的に何を行っていくか,そして目標とするところは何なのか,というところについて考えてみたいと思います。

「創作」と呼べるプログラムは存在する

もちろん,これはエンジニアリングに携わる人間としての観点です。

多くの人から見て,プログラミング言語という物はどれも大差がなく,結局「特定の条件に従って処理をする物」以上でも以下でもないのでしょう。

しかし,無秩序でないプログラム・プログラミング言語には何かしらの「設計思想」があり,そこにある「哲学」をベースとして書かれていることが多いのです。

例えばプログラミング言語であるLuaなどもその一種で,データ構造が非常に単純であることから習得が容易であり,かつ深く習得することでプログラミングにおける手法の殆どを実現することが出来,しかも高速に動作するという優れた環境を実現しています。

これは近年におけるJavaScriptも同様であり(個人的にLuaのほうが遥かにきれいで簡潔な設計だとは思いますが),Lightweight Language界のトレンドでもあります。

このような「汎用性に優れ,様々なプログラミングパラダイムを実現出来る言語」は「創作」と呼んでしまっても良いレベルに尊いものなのではないかと考えています。

Dirtyな言語でも「創作的」なコーディングは生きる

Dirty(汚い)言語として,良くphpが槍玉に挙げられます。phpは歴史的経緯から純粋なオブジェクト指向とはかけ離れた構文を多く持ち,引数の順序すらめちゃくちゃな多くのグローバル関数に支えられて動いています。

標準phpにおける連想配列は確かに便利ですが,オブジェクト指向的概念から考えたときにはあまりにも不便です。しかし,現代のphpはモダンなプログラミング環境を提供できるだけの機能を有しており,それらの機能を用いたモダンなオブジェクト指向をサポートするライブラリが十二分に提供されています。(例えばCollectionなど)

こういった再利用可能で汎用性に優れたライブラリを用いて書かれたコードは非常に見通しが良く,そのコードが一体何を行おうとしているのか,どのような役割を持っているのかがひと目で分かります。これはもはや芸術的とすら呼べるでしょう。

多くの人には理解されないでしょうが,私はこのような「見通しの良い設計」は「創作」の一つであると考えています。それほどまでに見通しの良いコードは尊く,人を幸せにする力があるのです。

「創作」と呼べるレベルのコードを書くためには

何よりも大事なのは,技術的トレンドを常に追い続けることです。しかし忘れてはならないのが,「それが本当に必要なものなのか」を考えることを怠ってはいけないという部分です。

技術的なトレンドは凄まじい勢いで移り変わっていきます。その激しい流れの中で,一体どれが物事の本質を見抜いているのか,それを見抜く力が必要になります。

設計における理想の実現は確かに大事かもしれません。しかし,それと全く同じ理想を持ち,冗長で複雑な処理を記述することを好む人がいるかと言えば,そんなことはないのです。

例えば有名なphp言語のWebアプリケーションフレームワークであるSymfonyとLaravelの関係を見てみましょう。Symfonyはそれぞれの機能がコンポーネントとして提供されており,疎結合かつSymfony以外のフレームワークからも容易に利用できる環境が整っています。

しかしLaravelはどうでしょう。実のところLaravelは機能の多くをSymfonyコンポーネントに依存しており,それを独自拡張する形で実現されている部分が大半です。また,LaravelはSymfonyほどコードの再利用性について考えられておらず,あくまでも「利用者がアプリケーションを作りやすい環境」を作ることに注力しています。

近年のphp言語におけるWebアプリケーションフレームワークではLaravelが圧倒的に人気となっています。Symfonyの人気は低くないものの,学習コストの高さや疎結合が故にアプリケーションの設計自体も利用者に委ねられるという点で,「手早くアプリケーションを構築したい」という需要を叶えにくい物となってしまっている背景があります。

しかしLaravelの基礎にはSymfonyの存在があり,皮肉にもLaravelはSymfonyがあるからこそ成り立つものなのです。

私はLaravelもSymfonyも「創作」と呼ぶにふさわしいプロダクトだと考えています。これらのプロダクトがあるからこそ今のモダンなphp開発環境が実現されているのであり,これらの作者には感謝してもしきれません。少なくとも,LaravelとSymfonyは私の心を動かしたのです。

最後に

自分が人の心を動かせるようなコードを書ける様になる日はまだまだ遠いか,もしくは一生ないかもしれません。

しかし,いつかは自分のコード・プロダクトで人の心を動かし,感動してもらえるようなものを作りたいと常々思っています。

家が燃えても気づける! @zeriyoshi_svr の裏側

みんなあるよね自宅サーバ

この界隈の人達にとって,自宅にサーバーがあるのは珍しいことではないかと思います。

特にファイルサーバーなんかは既製品を買ってくるよりも自作したほうが遥かに安く強力な物を作れるので便利です。

実際私も家にサーバーがあるのですが,WD Red 8TBx2をRAID1で構成し,ファイルサーバー兼Webサーバーとして稼働してもらっています。

この自宅サーバーなのですが,15分毎に室温+各種ハードウェアの温度をTwitterに投稿しています。

twitter.com

Twitterのフォロワーさんにこれを真似してくれている人が居たので,個人的なメモ代わりにもこのbotがどのようにして動いているかを書いておきたいと思います。

サーバー構成

  • CPU : Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz (4th Gen, Haswell)
  • RAM : 20GB (8GBx2, 2GBx2)
  • OS : Arch Linux (x86_64)

ハードウェアはそれなりにパワーがあるのですが,自宅の回線が細い(100Mbps VDSL)なのであまり有効に活用できない...

最近はもっぱらファイルサーバーとして活躍しています。

死活監視が出来ない

自宅の回線は特にISPの固定IPオプションなどを契約していない為,グローバルIPv4アドレスが定期的に変わる環境にあります。

その為にドメインレジストラのDynamic DNS機能を用いて逐次現在のIPアドレスを登録しているのですが,何かしらの問題が発生して登録が正常に行われない可能性があります。

こうなるとサーバーに物理的にアクセスできない限り現状の把握が出来ません。もしかしたら停電が起こっていたり,最悪サーバーが燃えている可能性も考えられます。

ならば"サーバー側から"現在の状況を報告もらえばいいのです。手持ちのUSB温度計があったので同時に室温も報告してもらうことにしました。

例えば室温が80℃とかになっていればそれはもう確実に家が燃えているので,安心してかなしい気持ちになることができます。(そう,燃えていることに気づけるだけです。)

なぜTwitterなのか

自分が一番良く見ているのがTwitterだから

(関係ないですが,私に連絡する時はメールとかLINEよりもTwitterでreplyかDMした方が反応がたぶん早いです...)

@zeriyoshi_svrを作ろう

では実際に作っていきたいと思います。

Twitter側作業

アカウントの作成

15分毎に自分のメインアカウントでつぶやかれるとフォロワーさんに迷惑です。ちゃんとbot用アカウントを作りましょう。メインアカウントで垂れ流そうものなら速攻でミュートに突っ込みます。

アプリケーション登録

Twitterにつぶやく為にはアプリケーションの登録が必要です。

先程作成したアカウントでログインした状態でTwitter Applicaton Managementにアクセスし,Create New Appボタンを押して登録を進めます。

Callback URLは空欄のままで大丈夫です。

アプリケーション権限変更

アプリケーションの登録は完了しましたが,初期状態ではTwitterに書き込む権限を有していません。

Twitter Applicaton Managementから先程作成したアプリケーションを開き,Keys and Access Tokensタブからmodify app permissionsを開いてRead and Writeに変更してください。

自身のアクセストークンを取得

権限の変更が完了したら,Keys and Access Tokensタブの下にあるYour Access TokenToken ActionからCreate my access tokenボタンをクリックして自身のアカウント用のアクセストークンを生成します。

Access Tokenが生成されたら,しっかりとAccess LevelRead and Writeになっていることを確認しましょう。

最後にアカウントのスクリーンネームと以下の4つのToken, Secretをメモしておきましょう。

サーバー側作業

ShellからTweet出来る環境構築

情報取得の前にまずShellからTweet出来る環境を整える必要があります。

ShellからTwitterにつぶやく為の方法はいくつかありますが,今回は非常にポータブルで使いやすい火を吹くTwitter怪人“小鳥男”を使っていきます。

使い方...は記事の方で詳細に説明されているので省略します。

で,問題はスクリプトをどこに置くかなのですが,当時の自分は何も考えずsudo su -した後/etc/zeriyoshiなるディレクトリを作ってそこに全てを突っ込むという凶悪な行為を行っていました。

本来であれば適切なパーミッションを設定した上で/optディレクトリ以下に置いたほうが良いでしょう。

温度情報の取得とTweetを行うスクリプトの作成

まずlm_sensorshddtempコマンドを用いるのでこれらをインストールします。

Linux ディストロによっては最初から入ってたりパッケージ名が違ったりするかもなので適宜確認してください。

$ sudo pacman -S lm_sensors hddtemp

で,ざっと次のようなスクリプトを書きます。

tweet_temp.sh

#!/bin/bash

cpu_temp=`sensors | grep Package | cut -c 17-24`
hdd_temps=""

for device in /dev/sd[abcd];do
    hdd_temps="${hdd_temps}${device}:`hddtemp -n $device` °C
";
done

echo -e "CPU:${cpu_temp}\nHDDs:\n${hdd_temps}\n`date +\"%Y/%m/%d %H:%M:%S\"`" | /etc/zeriyoshi/kotoriotoko/BIN/tweet.sh

はい。本当に適当です。各種実行ファイルのパスやデバイスノード名は環境に合わせて書き換えてください。

systemd-timerに登録しスクリプトを定期実行する

ちょっと前まではcronを使って定期実行を行うのが通例でしたが,最近のLinuxディストロは殆どがsystemdinitデーモンとして用いており,systemd自体にcron代替機能が備わっているのでそれを利用します。

まずはサービスを作成します。

$ sudo vim /etc/systemd/system/tweet_temp.service

[Unit]
Description=Tweet CPU and HDDs temperature.

[Service]
Type=oneshot
ExecStart=/etc/zeriyoshi/tweet_temp.sh

次にタイマーを作成します。

$ sudo vim /etc/systemd/system/tweet_temp.timer

[Unit]
Description=Tweet CPU and HDDs temperature.

[Timer]
OnCalendar=*:0/15

[Install]
WantedBy=timers.target

終わったらsystemdのデーモンを再読込し,タイマーを有効化して開始します。

$ sudo systemctl enable tweet_temp.timer
$ sudo systemctl start tweet_temp.timer

タイマーが正常に動作しているか確認します。

$ sudo systemctl | grep tweet_temp
  tweet_temp.timer                                                                                      loaded active waiting   Tweet CPU and HDDs temperature.                                   

これで一通り完了です。

おまけ : 室温をつぶやこう

@zeriyoshi_svrでは自宅の室温もつぶやいています。ではこれはどうやっているのかというと

f:id:zeriyoshi:20180108000443j:plain

こうしています。

こういうのと

www.itmedia.co.jp

これを組み合わせて

github.com

室内温度を測定しています。このUSB温度計は販売終了品となってしまっていますが,中国のR Ding社のOEM品なので今でも普通に入手することができます。

コンパイルにはlibusbが必要になるのでインストール後にmakeしてください。

GitHubの説明通り適切に設定を行えば管理者ユーザーでなくとも実行できるようになりますが,systemd-timerで実行している為特に設定はしていません。

デフォルトでは現在時刻が出力されてしまう&センサーの個体差で取得できる温度にブレがあるので通常の室温計を元にキャリブレーションを行い再度コンパイルしました。

一応ソースも貼っておきます。

pcsensor.cの修正patch(不要な変数宣言を消しているだけです)
--- pcsensor.c   2018-01-08 00:36:23.685319615 +0900
+++ pcsensor.fix.c    2018-01-08 00:34:36.358652434 +0900
@@ -47,7 +47,6 @@ const static char uCmd3[] = { 0x52,    0
 const static char uCmd4[] = { 0x54,    0,    0,    0,    0,    0,    0,    0 };
 
 const static int reqIntLen=8;
-const static int reqBulkLen=8;
 const static int timeout=5000; /* timeout in ms */
  
 static int debug=0;
temper.cを温度の出力のみ変更したpatch
--- temper.c 2018-01-08 00:40:19.838654085 +0900
+++ temper.zeri.c 2018-01-08 00:33:46.555318858 +0900
@@ -9,8 +9,8 @@
 
 /* Calibration adjustments */
 /* See http://www.pitt-pladdy.com/blog/_20110824-191017_0100_TEMPer_under_Linux_perl_with_Cacti/ */
-static float scale = 1.0287;
-static float offset = -0.85;
+static float scale = 1.00000;
+static float offset = -2.00;
 
 int main(){
    int passes = 0;
@@ -38,15 +38,7 @@ int main(){
        /* Apply calibrations */
        tempc = (tempc * scale) + offset;
 
-      struct tm *utc;
-      time_t t;
-      t = time(NULL);
-      utc = gmtime(&t);
-      
-      char dt[80];
-      strftime(dt, 80, "%d-%b-%Y %H:%M", utc);
-
-      printf("%s,%f\n", dt, tempc);
+       printf("%.3f °C\n", tempc);
        fflush(stdout);
 
        return 0;

あとは先程のtweet_temp.shを以下のようにするだけです。

#!/bin/bash

cpu_temp=`sensors | grep Package | cut -c 17-24`
hdd_temps=""

for device in /dev/sd[abcd];do
    hdd_temps="${hdd_temps}${device}:`hddtemp -n $device` °C
";
done

echo -e "Room:`/etc/zeriyoshi/temper`\nCPU:${cpu_temp}\nHDDs:\n${hdd_temps}\n`date +\"%Y/%m/%d %H:%M:%S\"`" | /etc/zeriyoshi/kotoriotoko/BIN/tweet.sh