matlab-find-pi-assets について
Industrial Communication Toolbox を使い、PI Data Archive のタグや PI Asset Framework のデータを照会する MATLAB スキルガイドです。タグ検索と AF 階層のナビゲーションを分け、読み取り前にサーバー、データベース、対象の確認を求めます。
主な機能
- 01名前や説明による PI タグ検索
- 02タグの現在値と履歴値の取得
- 03AF 要素、テンプレート、属性の探索
- 04AF 属性の時系列データ取得
- 05サーバー、データベース、検索結果の確認
活用シーン
- 01PI タグから現在値を照会
- 02指定期間の履歴データを取得
- 03名前やテンプレートで AF 資産を検索
- 04資産属性を確認してデータを取得
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ matlab/ matlab-agentic-toolkit --skill matlab-find-pi-assetsインストール後、Claude Code で/matlab-find-pi-assetsを入力して読み込まれたか確認します。
同梱ファイルmanifest.yamlreferences/key-functions.md
詳細
PI アセットの特定とデータのクエリ
MATLAB の Industrial Communication Toolbox ラッパーを使用して PI システムに接続し、アセットを検索して履歴データを読み取ります。生の .NET SDK 相互運用は使用しません。
リリース要件
| ワークフロー | 最低リリース | 関数 |
|---|---|---|
| A:PI Data Archive(タグ検索) | R2022a+ | piclient、tags、read(piclient) |
| B:PI Asset Framework(AF ナビゲーション) | R2026a+ | afclient、findElementByName、getAttributes、readHistory など |
使用する場面
- PI Asset Framework の要素または属性を検索、あるいはクエリしたい場合
- PI タグ名またはタグの説明が提示され、その検索を希望している場合
- PI AF 属性または PI タグの履歴データが必要な場合
- PI AF サーバー、PI Data Archive、OSIsoft、AVEVA PI、またはアセット階層について言及された場合
- テンプレートに基づいて要素を一覧表示したい場合(例:「すべての発電ユニット」)
使用しない場面
- AF 要素/テンプレートの作成または変更(管理)
- リアルタイムストリーミング、イベントフレーム、または通知
- PI Vision または PI Web API へのアクセス
- PI AF または PI Data Archive へのデータの書き戻し
判断ロジック
ユーザーから提示された情報に基づいてワークフローを選択します。
| ユーザーが提示するもの | ワークフロー | エントリー関数 |
|---|---|---|
PI タグ名(例:"GU1.ActivePower") | A:タグの直接検索 | piclient → tags |
| タグの説明またはタグ名の一部 | A:タグの直接検索 | piclient → tags |
| AF 内の要素名、テンプレート、または属性 | B:AF ナビゲーション | afclient |
| アセット階層の閲覧/探索のリクエスト | B:AF ナビゲーション | afclient |
不明な場合は、ユーザーに「特定の PI タグ名がありますか? それとも Asset Framework の階層をナビゲートする必要がありますか?」と尋ねます。
ワークフロー A:タグの直接検索(R2022a+)
ユーザーから PI タグ名または説明が提示された場合に使用します。
-
PI Data Archive サーバーを特定する(必ずユーザーに確認) — ユーザーがサーバー名を指定していない場合は、PI サーバー検出の手順(利用可能な PI Data Archive サーバーを検出するを参照)を実行して、利用可能なサーバーを列挙します。サーバーが見つからない場合は、ホストマシン上で検出可能な PI Data Archive サーバーがないことをユーザーに伝え、サーバー名を手動で提示するよう依頼します。サーバーが見つかった場合は、必ず一覧をユーザーに提示して、使用するサーバーを選択するよう依頼します。サーバーを自動選択したり、どのサーバーを使用するかを推測したりしてはいけません。説明がある場合はそれも含め、「該当なし」の選択肢も提示します。ユーザーが「該当なし」を選択した場合は、サーバー名を手動で提示するよう依頼します。ユーザーがサーバーを確認するまで、次の手順に進んではいけません。
-
接続する —
piObj = piclient('serverName') -
タグを検索する — ユーザーが提示した名前または説明を使用して、
tagList = tags(piObj, Name='pattern*')を実行します。 -
結果を提示する — 一致したタグをユーザーに提示し、確認を求めます。
tags()はTags列(文字列配列)を含むテーブルを返します。 -
データを読み取る —
tagName = tagList.Tags(N)でタグ名を取り出し、ユーザーの依頼内容に応じて選択します。- 現在値、または時間範囲が指定されていない場合:
data = read(piObj, tagName)— タグのスナップショット/現在値を返します。 - 時間範囲を指定した履歴データの場合:
data = read(piObj, tagName, DateRange=[start end], Interval=..., AggregateFcn=...)
ユーザーが「値を取得して」「現在の読み取り値は?」と言った場合、または日付範囲を指定せずにデータを求めた場合は、DateRange を指定せずに
read(piObj, tagName)を使用します。 - 現在値、または時間範囲が指定されていない場合:
ワークフロー B:Asset Framework ナビゲーション(R2026a+)
要素/属性の階層をナビゲートする必要がある場合に使用します。
-
AF サーバーを特定する(必ずユーザーに確認する) — ユーザーがサーバー名を指定していない場合は、AF サーバーの検出パターンを実行して、利用可能なサーバーを列挙します(利用可能な AF サーバーを検出するを参照)。サーバーが見つからない場合は、ホストマシン上で検出可能な AF サーバーがないことをユーザーに伝え、サーバー名を手動で指定するよう依頼します。サーバーが見つかった場合は、必ずユーザーに一覧を提示し、使用するサーバーを選択するよう依頼します。自動選択したり、使用するサーバーを推測したりしてはいけません。利用可能な場合は説明も含め、「該当するものがない」という選択肢も用意します。ユーザーが「該当するものがない」を選択した場合は、サーバー名を手動で指定するよう依頼します。ユーザーがサーバーを確認するまで次の手順に進んではいけません。
-
接続する —
afObj = afclient('serverName') -
データベースを確認する(必ずユーザーに確認する) —
listDatabases(afObj)を使って利用可能なデータベースを表示し、使用するデータベースをユーザーに選択するよう必ず依頼します。データベースが1つしかない場合でも、自動選択したり、使用するデータベースを推測したりしてはいけません。listDatabasesが返すのは名前のみの文字列配列です。名前と併せて説明を表示するには、.NET SDK の代替手段を使います(説明付きでデータベースを一覧表示するを参照)。ユーザーが対象の要素を含むデータベースがわからない場合は、データベース横断検索パターンを実行して、適切なデータベースを見つけます(すべてのデータベースを対象に要素を検索するを参照)。ユーザーがデータベースを確認するまで次の手順に進んではいけません。 特定したら、selectDatabase(afObj, dbList(N))またはafObj = afclient('serverName', Database='dbName')で接続します。 -
曖昧さを解消しながら要素を検索する — 関連する要素を見つけるには、必ずワイルドカード検索を使います。
- 検索:
results = findElementByName(afObj, 'baseIdentifier*')。baseIdentifierはユーザーが指定した最短の識別子です(例:「GU1 generator」から'GU1')。 - テンプレートで検索する場合:
elems = findElementByTemplate(afObj, 'templateName') - パスで検索する場合(完全なパスがわかっているとき):
elem = findElementByPath(afObj, "\\server\database\path\to\element")— 必ず文字列(二重引用符)を使い、文字ベクトル(単一引用符)は絶対に使わないでください。文字ベクトルを入力すると、パスが正しくてもエラーが返され、ひそかに失敗します。
検索結果は必ずユーザーに提示して確認を求めます。 返された要素の数にかかわらず、Name、Template、Description、矢印表記の階層パス(例:
Flynn River Hydro->Flynn I->GU1->GU1 Generator—\\server\database\のプレフィックスを取り除き、->で連結)、NumChildren を含む表をユーザーに提示します。どの要素を指しているのか、ユーザーに確認を求めます。ユーザーがさらに詳しい情報を求めた場合は、特定の要素に対してgetChildrenまたはgetAttributesを使って、ナビゲーションを支援します。ユーザーの確認後にのみ先へ進みます。 - 検索:
-
属性を取得して確認する — ワイルドカードの名前フィルターを指定して、
getAttributes(elem, 'attributeName*')を使用します。一致する属性が1つだけで、ユーザーのリクエストに明確に対応している場合は、そのまま進めます。重要 複数の属性が一致する場合、または曖昧さがある場合(例:「Active Power」と「Active Power Generated」、あるいは異なる要素に同じ名前の属性が複数ある場合)は、Name、ElementName、ServerDataType、DefaultUnit、HasTimeSeriesData、Descriptionを示す表で一致した属性を提示し、正しい属性を選択するようユーザーに尋ねます。要素名とデータ型は、異なる要素にある同名属性をユーザーが区別するのに役立ちます。 -
属性を検証する — ユーザーが属性を確認したら、データを読み取る前に以下を確認します。
- 親要素を確認する:
attr.ElementNameがユーザーの指定した対象アセットと一致することを確認します。階層全体を確認するには、attr.Path(形式:\\server\database\...\element|attribute)を使用します。ユーザーに表示する際は、\\server\database\のプレフィックスを削除し、->でつなぎます(例:Flynn River Hydro->Flynn I->GU1->GU1 Generator|Active Power)。要素がユーザーの指定とは異なるアセットを示している場合(例:兄弟要素にある類似名の属性)は、処理を進める前にユーザーに知らせます。 - 時系列データの有無を確認する: ユーザーが履歴データや期間指定のデータを要求していて、
HasTimeSeriesDataがfalseの場合、選択した属性には時系列データが含まれていないことをユーザーに伝え、代わりに現在値の読み取りを続行するか尋ねます。
- 親要素を確認する:
-
データを読み取る — ユーザーのリクエストに応じて選択します。
- 現在値、または期間の指定がない場合:
data = read(attr)— 属性のスナップショット値/現在値を返します - 期間を指定した履歴データ:
data = readHistory(attr, startTime, endTime, Interval=hours(1), AggregateFcn="average")
ユーザーが「値を取得して」「現在の読み取り値は?」と尋ねる場合、または日付範囲を指定せずにデータを要求する場合は、
read(attr)を使用します。 - 現在値、または期間の指定がない場合:
-
検証する — 返されたデータのステータスが有効であること(すべてが「Bad」またはNaNではないこと)を確認します。
主な関数
関数の一覧、属性のプロパティ、戻り値の型については、references/key-functions.md を参照してください。
パターン
利用可能なAFサーバーを検出する
NET.addAssembly('OSIsoft.AFSDK');
ps = OSIsoft.AF.PISystems;
numServers = ps.Count;
if numServers == 0
fprintf('No AF servers discovered on this machine.\n');
else
fprintf('Available AF Servers:\n');
for i = 0:numServers-1
serverName = string(ps.Item(i).Name);
desc = string(ps.Item(i).Description);
fprintf(' %d. %s\n', i+1, serverName);
if strlength(desc) > 0
fprintf(' Description: %s\n', desc);
end
end
end
numServers == 0 の場合、ホストマシンでサーバーを検出できないため、AFサーバー名を手動で指定するようユーザーに尋ねます。
利用可能なPI Data Archiveサーバーを検出する
NET.addAssembly('OSIsoft.AFSDK');
piServers = OSIsoft.AF.PI.PIServers;
numServers = piServers.Count;
if numServers == 0
fprintf('No PI Data Archive servers discovered on this machine.\n');
else
fprintf('Available PI Data Archive Servers:\n');
for i = 0:numServers-1
serverName = string(piServers.Item(i).Name);
desc = string(piServers.Item(i).Description);
fprintf(' %d. %s\n', i+1, serverName);
if strlength(desc) > 0
fprintf(' Description: %s\n', desc);
end
end
end
numServers == 0 の場合、ホストマシンでサーバーを検出できないため、PI Data Archiveサーバー名を手動で指定するようユーザーに尋ねます。
名前によるタグの直接検索
piObj = piclient('myPIServer');
tagList = tags(piObj, Name='GU1*');
disp(tagList)
tags() は Tags 列(文字列配列)を含むテーブルを返します。read() に渡す前に、tagList.Tags(N) でタグ名を取り出します。
PIタグから現在値を読み取る
期間を指定せずにPIタグの現在値/スナップショット値をユーザーが求めている場合に使用します。
piObj = piclient('myPIServer');
tagList = tags(piObj, Name='GU1.Active Power*');
tagName = tagList.Tags(1);
data = read(piObj, tagName);
disp(data)
PIタグから履歴データを読み取る
piObj = piclient('myPIServer');
tagList = tags(piObj, Name='GU1.Active Power*');
tagName = tagList.Tags(1);
startTime = datetime(2025, 1, 1);
endTime = datetime(2025, 2, 1);
data = read(piObj, tagName, DateRange=[startTime endTime], ...
Interval=hours(1), AggregateFcn="average");
disp(data)
サーバーとデータベースを確認しながらAFに接続する
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
fprintf('Connected to: %s\n', afObj.ServerName);
fprintf('Database: %s\n', afObj.Database);
説明付きでデータベースを一覧表示する
AFサーバーへの接続後、データベースを提示する際に使用します。listDatabases はデータベース名の 文字列配列 を返します(説明は含まれません)。名前と説明を併記するには、以下の.NET SDKによる代替手段を使用します。
afObj = afclient('myAFServer');
dbList = listDatabases(afObj);
fprintf('Available Databases on %s:\n', afObj.ServerName);
for i = 1:numel(dbList)
fprintf(' %d. %s\n', i, dbList(i));
end
説明を取得するには(.NET AFSDKが必要です):
NET.addAssembly('OSIsoft.AFSDK');
ps = OSIsoft.AF.PISystems;
afServer = ps.Item('myAFServer');
afServer.Connect();
fprintf('Available Databases on %s:\n', string(afServer.Name));
for i = 0:afServer.Databases.Count-1
db = afServer.Databases.Item(i);
dbName = string(db.Name);
desc = string(db.Description);
fprintf(' %d. %s\n', i+1, dbName);
if strlength(desc) > 0
fprintf(' Description: %s\n', desc);
end
end
テンプレートで要素を検索する
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
genUnits = findElementByTemplate(afObj, 'GenerationUnit');
disp(genUnits)
ワイルドカードを使って要素を検索し、確認する
親要素と子要素を見つけるため、常にベース識別子にワイルドカードを使用します。見つかった要素が1つだけの場合でも、結果を提示してユーザーに確認します。
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
results = findElementByName(afObj, 'GU1*');
fprintf('Found %d element(s) matching "GU1*":\n', numel(results));
for i = 1:numel(results)
pathParts = split(results(i).Path, '\');
hierarchy = strjoin(pathParts(4:end), '->');
fprintf(' %d. %s [Template: %s] Path: %s\n', ...
i, results(i).Name, results(i).Template, hierarchy);
if strlength(results(i).Description) > 0
fprintf(' Description: %s\n', results(i).Description);
end
end
fprintf('Which element would you like to proceed with?\n');
ユーザーの確認後(例:要素 2 =「GU1 Generator」)、ワイルドカードを使って属性を取得し、メタデータを表示します。
selectedElem = results(2);
attrs = getAttributes(selectedElem, 'Active Power*');
fprintf('Matching attributes on "%s":\n', selectedElem.Name);
fprintf(' %-4s %-20s %-20s %-14s %-14s %-10s %s\n', ...
'#', 'Name', 'Element', 'ServerDataType', 'Unit', 'TimeSeries', 'Description');
for i = 1:numel(attrs)
desc = attrs(i).Description;
if strlength(desc) == 0
desc = "(none)";
end
fprintf(' %-4d %-20s %-20s %-14s %-14s %-10d %s\n', ...
i, attrs(i).Name, attrs(i).ElementName, attrs(i).ServerDataType, ...
attrs(i).DefaultUnit, attrs(i).HasTimeSeriesData, desc);
end
一致する属性が1つだけで、ユーザーのリクエストに明確に該当する場合は、そのまま続行します。一致する属性が複数ある場合、または曖昧さがある場合(異なる要素に同じ名前の属性が複数ある場合を含む)は、上記の表を提示し、ユーザーに選択してもらいます。ElementName とデータ型は、同じ名前の属性を区別するのに役立ちます。
注:属性名は親要素と子要素で異なる場合があります(例:「GU1」には「Active Power Generated」があり、「GU1 Generator」には「Active Power」があります)。ワイルドカード検索では、複数の兄弟要素から同じ属性が返されることもあります(例:ウィンドファーム内のすべての発電機)。区別するには ElementName 列を使用します。
名前で要素を検索する(結果が1件の場合)
一致する要素が1つだけ返された場合でも、続行する前にその要素を提示してユーザーに確認します。
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
results = findElementByName(afObj, 'GU3 Turbine*');
fprintf('Found %d element(s) matching "GU3 Turbine*":\n', numel(results));
for i = 1:numel(results)
pathParts = split(results(i).Path, '\');
hierarchy = strjoin(pathParts(4:end), '->');
fprintf(' %d. %s [Template: %s] Path: %s\n', ...
i, results(i).Name, results(i).Template, hierarchy);
end
fprintf('Proceed with this element?\n');
確認後:
elem = results(1);
attr = getAttributes(elem, 'Active Power');
fprintf('Name: %s\n', attr.Name);
fprintf('Unit: %s\n', attr.DefaultUnit);
fprintf('Has Time Series: %d\n', attr.HasTimeSeriesData);
AF 属性から現在値を読み取る
ユーザーが期間を指定せずに、現在値、スナップショット、またはデータを求めている場合に使用します。
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
results = findElementByName(afObj, 'GU1*');
selectedElem = results(2);
attr = getAttributes(selectedElem, 'Active Power');
data = read(attr);
disp(data)
集計を使って履歴データを読み取る
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
elem = findElementByName(afObj, 'GU3 Turbine');
attr = getAttributes(elem, 'Cooling Water Output Temperature');
startTime = datetime(2025, 1, 1);
endTime = datetime(2025, 2, 1);
data = readHistory(attr, startTime, endTime, Interval=hours(1), AggregateFcn="average");
disp(data)
データ品質を確認する
readHistory と read は Status 列を含むテーブルを返します。値を使用する前に、「Bad」ステータスがないか確認してください。
badRows = data.Status == "Bad";
if all(badRows)
warning('All returned data has "Bad" status — no valid values in this time range.');
elseif any(badRows)
fprintf('%d of %d rows have "Bad" status.\n', sum(badRows), height(data));
end
値列の型はデータソースによって異なります:
- AF(
readHistory、read(attr)):Valueはセル配列です。数値を取り出すにはcell2mat(data.Value)を使用するか、data.Value{i}でインデックスを指定します。 - PI Data Archive(
read(piObj, tagName, DateRange=...)):Valueは double 配列です(数値に直接アクセスできます)。 - PI Data Archive の現在値(DateRange を指定せずに
read(piObj, tagName)を実行):Valueは文字列です(例:"Pt Created"またはテキスト形式の数値)。
getChildren で階層を参照する
afObj = afclient('myAFServer', Database='OSIDemo_PG_HydroPlant');
roots = getRootElements(afObj);
disp(roots)
children = getChildren(roots(1));
disp(children)
すべてのデータベースを対象に要素を検索する
探している要素がどのデータベースにあるかわからない場合に使用します。
afObj = afclient('myAFServer');
dbList = listDatabases(afObj);
elementName = 'GU1';
foundIn = {};
for i = 1:numel(dbList)
selectDatabase(afObj, dbList(i));
results = findElementByName(afObj, elementName);
if ~isempty(results)
foundIn{end+1} = dbList(i); %#ok<SAGROW>
end
end
if isempty(foundIn)
fprintf('Element "%s" not found in any database.\n', elementName);
else
fprintf('Element "%s" found in:\n', elementName);
for i = 1:numel(foundIn)
fprintf(' %d. %s\n', i, foundIn{i});
end
end
要素が複数のデータベースで見つかった場合は、一覧を提示し、正しいデータベースをユーザーに選んでもらいます。どのデータベースでも見つからない場合は、要素名を確認するようユーザーに依頼します。
規約
- Asset Framework へのアクセスには常に
afclientを使用してください。生の .NETOSIsoft.AFSDK相互運用は使用しないでください(例外:OSIsoft.AF.PISystems/OSIsoft.AF.PI.PIServersによるサーバー検出は許可されます)。 - PI Data Archive のタグへのアクセスには常に
piclientを使用してください。生の .NET 相互運用は使用しないでください(例外:サーバー検出)。 - 検出したサーバーは必ずユーザーに提示し、選択を求めてください。自動選択したり、選択を想定したり、省略したりしてはいけません。ユーザーがサーバーを確認するまで先に進まないでください。
- サーバーまたはデータベースの一覧を提示するときは、説明がある場合、名前とあわせて表示してください(説明の取得には .NET SDK によるフォールバックが必要です。
listDatabasesが返すのは名前のみです)。 - 検出したデータベースは必ずユーザーに提示し、選択を求めてください。自動選択したり、選択を想定したり、省略したりしてはいけません(データベースが 1 つしかない場合も同様です)。ユーザーがデータベースを確認するまで先に進まないでください。
- サーバー名が
'localhost'だと決めつけず、ユーザーに指定してもらうか、利用可能なサーバーから選択してもらってください。 findElementByPathおよびfindAttributeByPathのパス引数には、必ず文字列(二重引用符)を使用してください。文字(単一引用符)ではエラーなく失敗します。findElementByPath(afObj, "\\server\db\path")のように記述し、findElementByPath(afObj, '\\server\db\path')のようには記述しないでください。- 名前のフィルターを指定して
getAttributes(elem, 'name')を使用してください。すべての属性を取得してから文字列比較する方法は使用しないでください。 - テンプレートで要素を検索するには
findElementByTemplateを使用してください。テンプレート名を比較しながら階層を手動でたどる方法は使用しないでください。 - 親要素と子要素の両方を見つけるため、
findElementByName(afObj, 'baseIdentifier*')では必ずワイルドカードを使用してください。完全一致の名前だけで検索しないでください。 - 処理を進める前に、要素の検索結果(名前、テンプレート、説明、階層パス)を必ずユーザーに提示して確認を求めてください。要素が 1 つしか見つからない場合も同様です。
- ワイルドカードに一致する属性が複数ある場合や、あいまいな場合は、メタデータの表(名前、ElementName、ServerDataType、DefaultUnit、HasTimeSeriesData)を提示してユーザーに選択を求めてください。明確に一致する属性が 1 つだけの場合は、そのまま進めてください。
- ユーザーが階層の詳細を求めた場合は、
getChildren(elem)を使用して特定の要素の子要素を表示してください。 - ユーザーが「現在の値」や「データを取得」と尋ねた場合、または期間を指定していない場合は、
read(attr)またはread(piObj, tagName)(DateRange なし)を使用してください。期間が指定された場合に限り、readHistoryまたはread(..., DateRange=...)を使用してください。 - ユーザーがすでにタグ名を知っている場合は、
piclientとtagsを優先してください。不要に AF を経由しないでください。
よくある間違い
| 間違い | なぜ間違いなのか | 正しい方法 |
|---|---|---|
データクエリに NET.addAssembly('OSIsoft.AFSDK') を使用する | 冗長で、壊れやすく、不要です。MATLAB ラッパーが用意されています | afclient または piclient を使用します(AFSDK はサーバーの検出に限り使用できます) |
AF 要素のクエリに piclient を使用する | piclient は PI Data Archive のタグ用であり、AF 階層用ではありません | 要素/属性の移動には afclient を使用します |
ユーザーがタグ名を指定しているのに afclient を使用する | AF の移動機能は、タグを直接検索するには過剰です | piclient と tags(..., Name=...) を使用します |
サーバーが 'localhost' だと決めつける | サーバー名は環境によって異なります | ユーザーにサーバー名を尋ねます |
| 先にユーザーに確認せず、すべてのデータベースをスキャンする | 大規模なシステムではリソースを消費し、処理が遅くなります | 先にユーザーに確認します。ユーザーが判断できない場合に限り、すべてのデータベースをスキャンします |
| すべての属性を取得してから文字列でフィルタリングする | 属性が多い要素では非効率です | 名前フィルターを指定して getAttributes(elem, 'name') を使用します |
| テンプレートで要素を探すために、階層を手動でたどる | 深い階層では処理が遅く、エラーが発生しやすくなります | findElementByTemplate(afObj, 'templateName') を使用します |
検索結果をユーザーに見せずに findElementByName の結果を選ぶ | 親要素と子要素は名前の接頭辞が同じことがよくあります(例:GU1 と GU1 Generator)。ユーザーが子要素を指している場合でも、最初の一致が親要素である可能性があります | 常にワイルドカード検索('GU1*')を行い、Template/Path/Description を含むすべての結果を提示して、結果が 1 件だけの場合もユーザーに確認します |
属性を確認せずに readHistory に進む | 属性名は要素ごとに異なることがあり(例:「Active Power」と「Active Power Generated」)、ワイルドカードで複数の一致が返される場合があります。また、同じ属性名を持つ兄弟要素が複数ある場合もあります(例:風力発電所のすべての発電機) | 複数の属性が一致する場合や曖昧さがある場合は、メタデータ(Name、ElementName、ServerDataType、Unit、HasTimeSeriesData、Description)を表示し、ユーザーに選択を求めます |
ユーザーが現在値を求めているのに readHistory を使用する | readHistory には時間範囲が必要です。スナップショット値には過剰です | AF 属性には read(attr) を、PI タグには DateRange を指定せずに read(piObj, tagName) を使用します。履歴クエリの場合に限り、readHistory/DateRange を使用します |
findElementByPath または findAttributeByPath に char(シングルクォート)のパスを使用する | これらの関数は char 入力ではエラーを表示せずに失敗し、パスが正しくても「Unable to find」エラーを返します | 常に string(ダブルクォート)を使用します:findElementByPath(afObj, "\\server\db\path") |
listDatabases の結果を構造体として扱う(例:dbList(i).Name) | listDatabases が返すのは構造体ではなく文字列配列です。.Name にアクセスするとエラーになります | dbList(i) をそのまま使用します。すでに文字列です。selectDatabase(afObj, dbList(i)) に渡します |
属性に対して attrs(i).DataType を使用する | icomm.af.Attribute にこのプロパティは存在せず、実行時エラーになります | データ型の文字列には attrs(i).ServerDataType を使用します |
AF の結果に対する計算で data.Value を直接使用する | AF の readHistory/read(attr) が返す Value はセル配列のため、算術演算に失敗します | cell2mat(data.Value) を使用して、AF データから数値を取り出します |
Copyright 2026 The MathWorks, Inc.