OpenEnergyTools / scl-lib

5 stars 4 forks source link

tControl: Lookup GSE or SMV from control block #41

Closed danyill closed 1 year ago

danyill commented 1 year ago

I'd be keen to add a lookup of a GSE or SMV address element from a control block if this is agreed to be appropriate for this library.

The main subtlety is supporting ServerAt elements which is easy to forget.

I'm currently using:

/** @returns the cartesian product of `arrays` */
export function crossProduct<T>(...arrays: T[][]): T[][] {
  return arrays.reduce<T[][]>(
    (a, b) => <T[][]>a.flatMap(d => b.map(e => [d, e].flat())),
    [[]]
  );
}

function getCommAddress(ctrlBlock: Element): Element {
  const doc = ctrlBlock.ownerDocument;

  const ctrlLdInst = ctrlBlock.closest('LDevice')!.getAttribute('inst');
  const addressTag = ctrlBlock.tagName === 'GSEControl' ? 'GSE' : 'SMV';
  const ied = ctrlBlock.closest('IED')!;
  const iedName = ied.getAttribute('name');
  const apName = ctrlBlock.closest('AccessPoint')?.getAttribute('name');

  const cbName = ctrlBlock.getAttribute('name');

  let apNames = [];
  const serverAts = ied.querySelectorAll(
    `AccessPoint > ServerAt[apName="${apName}"`
  );
  if (serverAts) {
    const serverAtNames = Array.from(serverAts).map(ap =>
      ap.closest('AccessPoint')!.getAttribute('name')
    );
    apNames = [apName, ...serverAtNames];
  } else {
    apNames = [apName];
  }

  const connectedAps = `Communication > SubNetwork > ConnectedAP[iedName="${iedName}"]`;
  const connectedApNames = apNames.map(ap => `[apName="${ap}"]`);
  const addressElement = `${addressTag}[ldInst="${ctrlLdInst}"][cbName="${cbName}"]`;

  return doc.querySelector(
    crossProduct([connectedAps], connectedApNames, ['>'], [addressElement])
      .map(strings => strings.join(''))
      .join(',')
  )!;
}

I'd be happy to add some tests and contribute this at some point.

github-actions[bot] commented 1 month ago

:tada: This issue has been resolved in version 1.0.0 :tada:

The release is available on:

Your semantic-release bot :package::rocket: