2013年3月21日木曜日

PHP で MX Component

MELSEC-QのEthernetユニットというか、工場で使う三菱製品のEthernetがまともに動いてるのって見たことないんだけど…それはそれとして。

既に導入されてるシーケンサ(PLC)を置きかえるのは大変だから、おかしなEthernetユニットでも上手く誤魔化して動かしたり、するよね。三菱のシーケンサだったら通信の処理に「MX Component」を使っているケースもまぁまぁあると思う。

PHPではソケット通信ができるからMX Component使わなくても通信はできるんだけど、それだと保全の人が「わからない!」って騒ぎになっちゃうんだよね。というわけでPHPからMX Component を呼び出して通信する処理を書いてみたよ。

class ActMLEasyIf {
    const NO_ERROR = 0;
    private $com = FALSE;
    function __construct($LogicalStationNumber) {
        $this->com = new COM('ActMulti.ActMLEasyIF');
        if (FALSE === $this->com) {
            throw new Exception('MX Componentを読み込めませんでした');
        }
        $stationNumber = new VARIANT(intval($LogicalStationNumber));
        $this->com->ActLogicalStationNumber = $stationNumber;
        if (ActMLEasyIf::NO_ERROR != $this->com->Open()) {
            throw new Exception('PLCに接続できませんでした');
        }
    }
    function __destruct() {
        $this->com->Close();
    }
    function readDeviceBlock2($address, $length) {
        $buf = new VARIANT(array_fill(0, $length, FALSE), VT_ARRAY | VT_VARIANT);
        $ret = $this->com->ReadDeviceBlock2(
            new VARIANT($address),
            new VARIANT($length),
            $buf);
        if (ActMLEasyIf::NO_ERROR != $ret) {
            throw new Exception('readDeviceBlock2の実行中にエラーが発生しました');
        }
        $values = array();
        foreach($buf as $value) {
            $values[] = $value;
        }
        return $values;
    }
}

とりあえず読み込むところだけ書いてみると、こんな感じ。PHPのVARIANTは使わなくても大丈夫っぽいけど念のため。これを使う時は…

$PLC = new ActMLEasyIf(5);
$data = $PLC->readDeviceBlock2('D0', 10);

こんな感じ。簡単だね。

あ、そうそう。当然と言えば当然なんだけど、PHPでCOMを使うためにはWindows環境が必要だよ。php.iniを編集してphp_com_dotnet.dllを有効にするとCOMが使えるようになるよ。

ちなみにここに書いたコード、ページを表示する度にOpenとCloseが繰り返されるはずで、普通に考えたら問題ないはずなんだけど実際には上手く動かないよ。三菱のEtherユニットの不具合というか仕様バグを見極めて、上手く誤魔化せばいちおー使えるんだけど。

IISでアプリケーション書いたら接続を管理できるから問題ないと思うんだけどね。現場のPCがWindows XP Home Editionで、置きかえも追加もできなくて、現場の人が対応できる限界が「XAMPP」だったから、PHPで書いてみたんだ。