ブログ

割とコンピュータよりの情報をお届けします。

コンピュータ

Python for .NETの新しい話

だいぶん前に「PythonからC#で書いた.NET Framewokのクラスライブラリを読みだす」1つ目2つ目
では.NET Frameworkのプログラムを読み出すことだった。

逆の「C#からPythonの関数を呼び出し」は更新が追い付いていないといって最新版をとってきていた。
多少最新バージョンからバージョンがずれていてもよいならpythonnet_py37_winなどなどnugetで入れられるようになっていた。むしろこちらの方が簡単だな。

nugetパッケージは.NET Frameworkならpythonnet_py37_winだし.NET Coreならpythonnet_netstandard_py37_win
やっぱりnugetパッケージは簡単.ただし,embeddable pythonをビルドターゲットフォルダに持ってきている。この参考でscipyまたはnumpyをインストールした方が便利。

ターゲットに入れて一緒に持ち運び....(scipyまで入れると相当 大きい)

using Python.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PythonEmbedSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string strPath = Environment.GetEnvironmentVariable("PATH");

            string appDir = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + @"\python";

            Environment.SetEnvironmentVariable("PATH", Path.PathSeparator + appDir, EnvironmentVariableTarget.Process);

            using (Py.GIL())
            {
                PythonEngine.RunSimpleString("print('SAMPLE')");
            }
        }
    }
}

python37._pthの#import siteのコメントアウトを解除して,https://bootstrap.pypa.io/get-pip.pyをもらってきて,...
embeddable pythonのディレクトリでpython get-pip.pyを実行して,
python -m pip install scipyを実行して... scipyを使えるようになった

例えば,sample.pyを作る splineで補間する例を追加してみた.

import numpy as np
from scipy import interpolate

def spline(x, y, xi):
    x = np.array(x);
    y = np.array(y);
    xi = np.array(xi);
    f = interpolate.interp1d(x, y, kind="cubic", fill_value="extrapolate")
    yi = f(xi);
    return yi;

そしてC#の側を次のようにいじってsample.pyのモジュールを読み込むようにする.

using Python.Runtime;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace PythonEmbedSample
{
    class Program
    {
        static void Main(string[] args)
        {
            string strPath = Environment.GetEnvironmentVariable("PATH");

            string appDir = Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName + @"\python";

            Environment.SetEnvironmentVariable("PATH", Path.PathSeparator + appDir, EnvironmentVariableTarget.Process);

            using (Py.GIL())
            {
                dynamic sys = Py.Import("sys");
                // sample.pyを置くフォルダをパスに追加
                sys.path.append(Directory.GetParent(Assembly.GetExecutingAssembly().Location).FullName);


                dynamic sample = Py.Import("sample");
                
                List<double> x = new List<double>(); // Python listへの変換予定
                List<double> y = new List<double>(); // Python listへの変換予定

                for (int i = 0; i < 10; i++)
                {
                    x.Add(0.1 * i);
                    y.Add(Math.Sin(2.0 * Math.PI * x[i] / 1.0));
                }

                List<double> xi = new List<double>(); // Python listへの変換予定
                for (int i = 0; i < 100; i++)
                {
                    xi.Add(0.01 * i);
                }
                dynamic yi_ = sample.spline(x, y, xi); // numpy.arrayで返ってくる予定
                List<double> yi = new List<double>(); // List<double>への変換は暗黙的にできないため
                yi.AddRange((double[])yi_);

                {
                    StreamWriter sw = new StreamWriter("sample_init.csv");
                    for (int i = 0; i < x.Count; i++)
                    {
                        sw.WriteLine(string.Format("{0},{1}", x[i], y[i]));
                    }
                    sw.Close();
                }

                {
                    StreamWriter sw = new StreamWriter("sample_interp.csv");
                    for (int i = 0; i < xi.Count; i++)
                    {
                        sw.WriteLine(string.Format("{0},{1}", xi[i], yi[i]));
                    }
                    sw.Close();
                }
            }
        }
    }
}

≫ 続きを読む

2021/02/17 コンピュータ   TakeMe
Tag:Python

BaserCMSのサイト内検索ができない

最近サーバーを入れ替えたが,どうもその前からサイト内検索ができなくなっていたようだ.
全く気付かなかった.

BaserCMSのバグかと思い,ユーザーフォーラムを確認すると,
どうも少し内容が違うが,記載された現象も生じている.

実際にこのサイトの先頭ページでサンプルを作ってみた(トップページの「サイト内検索」は現在動作しません)
このBaserCMSのデータベースをMySQLに移したときとPostgreSQLに移したときとSQLite3に移したときとで動作が異なる.
内部エラーになるか0件と表示されるか.

データベースを入れ替えるとエラー表示だけは消えるので開発側で良く使うデータベースだけ問題が起きないのかと思っている.

ただし,このサイトの場合にはソースコードも書いてしまっているのでセキュリティ的にまずいので止めるように変更されたのかもしれない.
いずれにしても,トップページの「サイト内検索」は現在動作しません もはやいつからかわからないがサーバ入れ替え前にこの状態だったようだ.

≫ 続きを読む

2021/02/06 コンピュータ   TakeMe

OpenTKの参考ページをいろいろ探していた

OpenTKの参考ページを探していた。かなりたくさんの情報が盛り込まれているページは鳩でもわかるC#
OpenTKだけの参考本はほぼないかもしれない。

Windows FormsやWPFで簡単に GPUを使った描画をやらせたいと思っていた時に,OpenTKの記事が参考になった.

記事では,手動でOpenTKのライブラリを追加しているが,これはopentkのライブラリをインストールさせるところから始まっているため。

nugetパッケージをとってくるのが一番簡単かな。nugetパッケージで入れてやるとビルド時も実行に必要なファイルはターゲットディレクトリに書き出してくれる。ツールボックスからGLControlがドラッグアンドドロップできる状態にもできる。

nugetでは「OpenTK」ではなく「OpenTK.GLControl」を探して選択してインストールして,OpenTKが合わせてインストールされる状態に持っていく方がよさそう。
しばらく参考を見てみるところ。

-- 
参考ページ

 

≫ 続きを読む

2021/01/31 コンピュータ   TakeMe

VirtualBoxにUEFIモードでUbuntuをインストールすると

UEFIでは本当は不揮発性メモリにブートオーダを記憶することになるらしい.

仮想環境によっては,一度インストールするとそのままではisoファイルを起動デバイスにできない.

実際のPCではメーカによって起動順序を変える操作が可能になっているが,VirtaulBoxの仮想環境では,仮想ハードディスクに何も入っていないときにはCD/DVDドライブから起動できる.ところが,一度インストールすると起動デバイスが固定されるのではBIOSモードのようにF12などのキーを押していても仮想ハードディスクから起動するのでCD/DVDドライブから起動できない.
仮想環境では普通は新しい仮想ハードディスクを用意するからそのような仕様になっているのかと思う.ただし,isoファイルから起動したいことがあった.

sudo efibootmgr --bootorder '0001,0004,0000,0003,0002'

などを実行するとVirtualBoxでも起動順序を制御できる.

≫ 続きを読む

2020/05/05 コンピュータ   TakeMe

Mondo Rescueが戻ってくるらしい

Mondo Rescueが戻ってきたらしいというのが正しいか?
Mondo Rescue最新版がもう少しでリリースされそう.というか3.3.0が新しいバージョンのようなのでリリースされたのか.
過去に書いた記事の訂正もふくめてもう一度確認した. 

Mondo Rescueは新しいバージョンの準備が進んでいるようだ.ubuntu用に使用できるパッケージも戻ってくるかもしれない.既にリポジトリにはMondo 3.3.0なるあたらしそうなバージョンがあがっている。
ところで,過去の記事では以下のようにすればmondo rescueをインストールできると書いていたが,これは今でも有効である

# wget http://www.mondorescue.org/ftp/ubuntu/16.04/mondorescue.sources.list
# sudo mv ./mondorescue.sources.list /etc/apt/sources.list.d/
# sudo apt-get update
# sudo apt-get install mondo

これだけだと sudo apt-get updateの後に「以下の署名は検証できませんでした: NO_PUBKEY 6BA8C2D220EBFB0E」などと出るので,

# sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6BA8C2D220EBFB0E
# sudo apt-get update
# sudo apt-get install mondo

と実行していく必要もある.

確認したところ,Ubuntu 18.04でも16.04のリポジトリを指定したまま使えた(16.04用のリポジトリのパッケージそのままインストールして使える)
少なくとも,Ubuntu 18.04でもapt-get install mondoでインストールは成功する.
どうもhttp://www.mondorescue.org/ftp/ubuntu/****/を開くと足りないパッケージがある場合には一つ前のバージョン用のバージョン用を足せば良いようだ.
/etc/mindi/mindi.confの編集も必要だ(新バージョンでは修正があったので多くの場合 mindi.confの編集が不要になったらしい.新しいバージョンの組み合わせを使ってほしいようだ).
ただし,仮想環境で確認していると,mondoarchiveはUEFIモードでインストールされたUbuntuの場合には実行中に失敗するなんでだろう(debian/ubuntu版の既知の問題らしい3.3.1以降になりそう)

多くのVPSサービスの場合,UEFIモードのようなESPパーティションを持たせないためBIOSモードが多いらしい.そう考えるとdebian/ubuntuでUEFIモードに非対応でも有用であることに変わりない.

≫ 続きを読む

2020/05/03 コンピュータ   TakeMe

SQLiteのデータベースファイルへの同時アクセス4

7月の記事ではMicrosoft Chart ControlsではDataBind()が遅いと指摘していたが,使っているうちにそれだけでなくPoints.Clear()が異常に遅いことに気が付いた.

Microsoft Chart ControlsではSeries(系列)をIDEのプロパティ編集で調整できるので,系列を残しておきたい衝動に駆られる.つまり,表示するデータを入れ替えるときには,系列は残してPointsだけを削除したくなる.

しかし,遅い.

Series.RemoveAt()で系列そのものを消した方が数百倍速くなる.
難しい.

≫ 続きを読む

2020/01/25 コンピュータ   TakeMe

ConoHaのUbuntuにLubuntuのGUIを入れてみた

ConoHaのVPSでサーバを借りていた.通常は管理ツールがみんなコマンドラインなのだけど.GUIにあこがれてlubuntu-desktopを入れてしまった.

ConoHa VPSはテンプレートに近い設定なら,近ければ近いほど運用が楽なようになっている.
できればUbuntu 18.04のテンプレートを使いたい.
Ubuntu 18.04のサーバの部分がインストールで出来たら,ユーザを追加してsshでログインできるように設定する.

さらに,

sudo aptitude install language-pack-ja-base language-pack-ja ibus-mozc

を実行しておく(ibus-mozcはおそらくfcitx-mozcの間違いではないかと思う).さらに,以下を実行して

sudo update-locale LANG=ja_JP.UTF-8 LANGUAGE="ja_JP:ja"

再起動するか source /etc/default/localeで設定を反映する.ここまで来てしまうとConoHaのコンソールでテキストベースでログインしなおすとことごとく文字化けが発生するようになっている.
この後以下を実行してlubuntu-desktopの部分を入れる

sudo aptitude install lubuntu-desktop

ここまでで,ConoHaのコンソールから開くとテキストベースでなくてvncでGUIのログインができるようになっている.日本語サーポートの追加もしておいた方が良いかもしれない.
 私は以下を追加した.(先ほどibus-mozcを間違って入れてしまっているから)

sudo apt install fcitx-mozc
sudo apt install fonts-noto-cjk fonts-noto-color-emoji

ところで,手元のクライアントWindowsにX Server(私はX410を買った)があれば,PuttyなどでログインしてX11ForwardingでGUIを手元に開けることも可.その場合には,次のようなスクリプトを実行するとよい.手元Windowsが日本語キーボードになっている場合にはlxsessionを始める前に,xset -r 49が必要だ(手元のWindowsのキーボードがENG表示ならこれはいらない).

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export DefaultIMModule=fcitx

fcitx-autostart

lxsession -s Lubuntu -e LXDE
 

音以外はこれで良い.音はPulseAudioを使わないとクライアントに持ってこれない.

ちなみに,うえのスクリプトではパネルまで全部起動するのだが,ターミナルだけで良ければ

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS=@im=fcitx
export DefaultIMModule=fcitx
xset -r 49
fcitx
lxterminal

≫ 続きを読む

2019/11/02 コンピュータ   TakeMe

Windows Embedded でのMessageBoxの扱いの注意

Windows Embedded Standard向けのアプリを開発していたら,.NETで64bitでも32bitでもどちらでもアプリが動かしるようにしていたところ,32bitでの動作では普通にMessageBoxが開くのに...

組み込み用のWindowsではWindows標準のMessageBoxの動作を変更することができる.すべてOKを応答させてダイアログを表示させないようにするのだ.

.NET Frameworkで開発したアプリで特に64bitで動かしたときにできるらしい.
この機能は開発時にMessageBoxを出させておいて,展開時にはMessageBoxを抑制するというという使い方になる.
知らなかったのでダイアログが出ない理由を一週間かけて探した.

≫ 続きを読む

2019/10/19 コンピュータ   TakeMe

WinPython 3.7.4はVSCode付もあるVol. 2

WinPython 3.7.4はVSCode付きもあるのでUSBメモリに搭載して環境を移動することも可能である.
ということで調子に乗ってPythonの開発環境をSDカードに設けていたら,2週間でデータが吹っ飛んだ.

VSCodeを使うPythonの開発環境は,安全な取り外しができない(ことが多い).
最初は問題ないと思っていたが,

使用開始2週間たつと異常に気付く.新しいフォルダを作ると作ったつもりのないファイルが現れる.最初は新種のウイルスかと思ったが,どうもFATのファイルを管理している領域がまず破壊されたようだ.(安全な取り外しができないときに起きることがある典型的な症状)

新品SDカード32GBを失った.

悔しいのでEaseUS Data Recovery Wizard Freeを使ってデータだけでも復旧を試みるが,WinPythonのたくさんのファイルが邪魔をして一回目はうまくいかなかった(復旧ファイルを間違えた).この時点でFree版の制限容量を使い切ってしまった.
まだ悔しいので,EaseUS Data Recovery Wizard Professionalを購入してどうしても欲しいものだけ復旧(結局4時間かかった).(9割以上復旧に成功)

間違って消したファイルの復旧系はフリーソフトでもできることがあるが,読み取り可能な状態でファイルシステムが消失したSDカードはこのソフトがいいらしい.(このソフトでも認識さえしなくなったSDカードの場合には無理)

≫ 続きを読む

2019/10/16 コンピュータ   TakeMe

どこでもセンサーを購入

プラネックスコミュニケーションズのどこでもセンサーを購入した.
どこでも環境センサーとどこでも人感センサーをひとつづつ.

まず,どこでもセンサーはセンサーの取得した値をクラウドに上げている.しかも利用料は今のところ無料である。クラウドに上げてチャートを見られるサービスはほかの商品でも見られるが,この商品の違うところはAPIを使うと自分のアプリケーションでデータを使用できること.

しかし,人感センサーは使い物にならないかな(と思う).人がいないのに数百カウントしてしまう.感度の問題と思っていたが感度を下げても改善されない.

環境センサーの方はいったん接続が途切れた時にすぐに復帰を試みるのだが,その際に温度計の取得する値が上昇する.しばらくすると値が落ちていくことからすると,自分の制御処理系の発熱も感じているとみえる。

気を付けないと使えないかも.しかもAPIもレスポンスに503ばかりがかえってくる.これは,改善を目指しているようだが作りが荒い。といっても,クラウドサービスを無料にしている関係でやむを得ないのか

var request = require('request');
var fs = require('fs')
var mongodb = require("mongodb");
var client = mongodb.MongoClient;
var url = "mongodb://username:password@localhost:27017/dbname";
var dbName = 'dbname';
var colName = 'dokodemosensors';

var getDatum = function(uri, mac, token) {
  var options = {
    url: uri,
    method: 'GET'
  }

  //リクエスト送信
  request(options, function (error, response, body) {
    //コールバックで色々な処理
    console.log(body);
    console.log(mac);
    
    var json = null;
    try {
      if (response.statusCode == 200) {
        json = JSON.parse(body);
        writeDataSafe(json, mac);
      } else {
      }
    }
    catch (e)
    {
      console.log('error');
    }

  });
};

var CheckIn = function(mac, token) {
  client.connect(url, (error, db) => {
    var col = db.db(dbName).collection(colName);
    col.find({'mac': mac}, { sort: { date: -1 }, skip: 0, limit: 1 })
      .toArray()
      .then((docs) => {
        var date = new Date();
        date.setDate(date.getDate() - 31);
        if (docs.length > 0) {
          date = docs[0].date;
        }
        date.setHours(date.getHours() - 9);
        dateto = new Date(date)
        dateto.setDate(dateto.getDate() + 31);
        var dateStr = date.getFullYear() + "-"
          + ('0' + (date.getMonth() + 1)).slice(-2) + "-"
          + ('0' + date.getDate()).slice(-2) + " "
          + ('0' + date.getHours()).slice(-2) + ":" 
          + ('0' + date.getMinutes()).slice(-2) + ":" 
          + ('0' + date.getSeconds()).slice(-2);
        var dateStrTo = dateto.getFullYear() + "-"
          + ('0' + (dateto.getMonth() + 1)).slice(-2) + "-"
          + ('0' + dateto.getDate()).slice(-2) + " "
          + ('0' + dateto.getHours()).slice(-2) + ":" 
          + ('0' + dateto.getMinutes()).slice(-2) + ":" 
          + ('0' + dateto.getSeconds()).slice(-2);
          
        var uri = 'api' + '?type="WS-USB01-THP"&mac="' + mac + '"&from="'
          + dateStr
          + '"&to="'
          + dateStrTo
          + '"&token="' + token + '"'
        console.log(uri);
        getDatum(uri, mac, token)
      })
      .catch((err) => {
        console.log(err);
        console.log('error');
      })
      .then(() => {
        db.close();
      });
  });
}

var writeDataSafe = function(json, mac) {
  for (var i = 0; i < json.length; i++) {
    var dt = new Date(Date.parse(json[i][0] + ' GMT'));
    json[i][0] = dt;
    json[i][1] = parseFloat(json[i][1])
    json[i][2] = parseFloat(json[i][2])
    json[i][3] = parseFloat(json[i][3])
  }
  var jsons = [];
  for (var i = 0; i < json.length; i++) {
    item = {'date': json[i][0], 'temperature': json[i][1], 'humidity': json[i][2], 'atomospheric pressure': json[i][3], 'mac': mac};
    jsons.push(item);
  }
  
  client.connect(url, (error, db) => {
    var col = db.db(dbName).collection(colName);
    if (jsons.length > 0) {
      
      for (var i = 0; i < jsons.length; i++) {
        col.update({"date": jsons[i].date, 'mac': jsons[i].mac},
          jsons[i],
          {'upsert': true}, function(error, result) {
          this.db.close();
        }.bind({'db': db}));
      }
      setTimeout(function() {
        this.db.close();
        console.log('timeout');
      }.bind({'db': db}), 30000);
    }
  });
}

CheckIn('mac', 'token')

setInterval(function () {
  CheckIn('mac', 'token')
}, 210000);

≫ 続きを読む

2019/10/15 コンピュータ   TakeMe