s7webserverapi
Version:
Unofficial Simatic-S7-Webserver JSON-RPC-API Client for S7-1200/1500 PLCs
234 lines (233 loc) • 9.08 kB
TypeScript
import { Observable } from "rxjs";
/**
* When having a nested object T, this will create a type that Flattens the keys.
* e.g. for {a: {b: {c: 0}}} it will create the keys:
* "a", "a.b", "a.b.c"
*
* @export
* @typedef {FlattenKeys}
* @template T
* @template {string} [Prefix=""]
*/
export type FlattenKeys<T, Prefix extends string = ""> = T extends "Structureless" ? string : T extends object ? {
[K in keyof T]-?: K extends string | number ? `${Prefix}${K & string}` | FlattenKeys<T[K], `${Prefix}${K & string}.`> : never;
}[keyof T] : "";
export type PlcPermissions = "read_diagnostics" | "read_value" | "write_value" | "acknowledge_alarms" | "open_user_pages" | "read_file" | "write_file" | "change_operating_mode" | "flash_leds" | "backup_plc" | "restore_plc" | "manage_user_pages" | "update_firmware" | "change_time_settings" | "download_service_data" | "change_webserver_default_page" | "read_watch_table_value" | "write_watch_table_value" | "read_syslog";
export type S7DataTypes = string | number | boolean | object | S7DataTypes[] | {
[key: string]: S7DataTypes;
};
export interface S7JsonClient<T> {
get<K = S7DataTypes>(key: FlattenKeys<T> | FlattenKeys<T>[], cacheMode?: CacheMethod, depth?: number): Observable<K>;
write<K = S7DataTypes>(key: FlattenKeys<T>, value: K): Observable<S7DataTypes>;
subscribe<K = S7DataTypes>(key: FlattenKeys<T> | FlattenKeys<T>[], ignoreCache?: boolean): Observable<{
value: K;
changedKey: string;
}>;
currentUser: string;
can(permission: PlcPermissions): boolean;
getPermissionsUpdates(): Observable<PlcPermissions[]>;
login(user: string, password: string): Observable<true | {
code: RPCErrorCode;
message: string;
}>;
downloadFile(path: string, binary?: boolean): Observable<string>;
downloadFolder(folderPath: string): Observable<(FileBrowseResult & {
data: string;
})[]>;
browsePath(path: string): Observable<FileBrowseResult[]>;
closeAllTickets(): Observable<boolean>;
browseTickets(): Observable<BrowseTicketsResult>;
closeTicket(ticketId: TicketID): Observable<CloseTicketResult>;
downloadTicket(ticketId: TicketID, type: "text" | "arrayBuffer" | "json"): Observable<string>;
uploadToTicket(ticketId: any, data: TicketID): Observable<boolean>;
uploadFileToWebApp(application_name: string, filename: string, media_type: string, data: string, isProtected?: boolean, etag?: string, last_modified?: string | Date): Observable<boolean>;
webAppCreate(name: string, enabled?: boolean): Observable<boolean>;
webAppDelete(name: string): Observable<boolean>;
webAppRename(name: string, new_name: string): Observable<true>;
webAppBrowse(name?: string): Observable<WebAppBrowseResponse>;
webAppSetState(name: string, enabled: boolean): Observable<boolean>;
webAppSetDefaultPage(name: string, resource_name: string): Observable<boolean>;
webAppSetNotFoundPage(name: string, resource_name: string): Observable<boolean>;
webAppBrowseResources(app_name: string, resource_name?: string): Observable<WebAppBrowseResourcesResponse>;
webAppCreateResource(app_name: string, resource_name: string, media_type: string, isProtected?: boolean, etag?: string, last_modified?: string | Date): Observable<TicketID>;
webAppDeleteResource(app_name: string, resource_name: string): Observable<boolean>;
webAppRenameResource(app_name: string, resource_name: string, resource_new_name: string): Observable<boolean>;
webAppDownloadResource(app_name: string, resource_name: string): Observable<TicketID>;
webAppSetResourceVisibility(app_name: string, resource_name: string, is_protected: boolean): Observable<boolean>;
webAppSetResourceETag(app_name: string, resource_name: string, etag: string): Observable<boolean>;
webAppSetResourceMediaType(app_name: string, resource_name: string, media_type: string): Observable<boolean>;
webAppSetResourceModificationTime(app_name: string, resource_name: string, last_modified: string | Date): Observable<boolean>;
webAppSetVersion(app_name: string, version: string): Observable<boolean>;
webAppSetUrlRedirectMode(app_name: string, redirect_mode: string): Observable<boolean>;
}
export type TicketID = string;
export interface WebAppBrowseResourcesResponse {
max_resources: number;
resources: WebAppBrowseResourcesResourceResponse[];
}
export interface WebAppBrowseResourcesResourceResponse {
name: string;
size: number;
media_type: string;
etag?: string;
visibility: "public" | "protected";
last_modified: string;
}
export interface WebAppBrowseResponse {
max_applications: number;
applications: WebAppBrowseApplicationsResponse[];
}
export interface WebAppBrowseApplicationsResponse {
name: string;
state: "enabled" | "disabled";
type: "user" | "vot" | "system_builtin";
version?: string;
redirect_mode: "forward" | "redirect";
default_page?: string;
not_found_page?: string;
not_authorized_page?: string;
}
export declare enum CacheMethod {
USE_CACHE = 0,
IGNORE_CACHE = 1,
WAIT_FOR_WRITE = 2,
USE_WRITE = 3
}
export interface S7WebserverClientConfig<T> {
plcStructure?: {
[key: string]: any;
};
/**
* Settings for the polling-process.
* Uses Exponential Moving Average to control the polling-delay.
* To fine tune it, you can set the parameters here.
*
*/
localStoragePrefix: string;
defaultUser?: {
user: string;
password?: string;
};
polling?: {
clamp?: boolean;
minDelay?: number;
slowMinDelay?: number;
emaAlpha?: number;
};
initialCacheKeys?: FlattenKeys<T>[];
/**
*
*/
debug?: boolean;
prefixSubstitutionMap?: PrefixSubstitutionMap<T>;
}
export type PrefixSubstitutionMap<T> = {
[dbName in FlattenKeys<T>]?: string;
};
export type RPCVarTypeSimple = number | string | boolean;
export type RPCVarTypeRaw = number[];
export interface RPCMethodObject<T = Params> {
jsonrpc: string;
method: string;
params?: T;
id: string;
}
export interface RPCResponse<T extends RPCResults> {
jsonrpc: string;
result?: T;
error?: {
code: RPCErrorCode;
message: string;
};
id: string;
}
export declare enum RPCMethods {
Ping = "Api.Ping",
Login = "Api.Login",
Read = "PlcProgram.Read",
Write = "PlcProgram.Write",
GetCertificateUrl = "Api.GetCertificateUrl",
GetPermissions = "Api.GetPermissions",
BrowseFiles = "Files.Browse",
DownloadFile = "Files.Download",
BrowseTickets = "Api.BrowseTickets",
CloseTicket = "Api.CloseTicket"
}
export type RPCResults = LoginResult | WriteResult | GetCertificateUrlResult | ReadResult | GetPermissionsResult | PingResult | BrowseFilesResult | DownloadFileResult | BrowseTicketsResult | CloseTicketResult;
export type Params = LoginParams | ReadParams | WriteParams | GetCertificateUrlParams | GetPermissionsParams | PingParams | BrowseFilesParams | DownloadFileParams | BrowseTicketsParams | CloseTicketParams;
export type FilesParams = {
resource: string;
};
export type BrowseFilesParams = FilesParams;
export interface FileBrowseResult {
name: string;
type: string;
size?: number;
last_modified: string;
state?: string;
}
export type BrowseFilesResult = {
resources: FileBrowseResult[];
};
export type CloseTicketParams = {
id: string;
};
export type CloseTicketResult = boolean;
export type BrowseTicketsParams = {
id?: string;
} | null;
export type BrowseTicket = {
id: string;
date_created: string;
provider: string;
state: string;
data?: object;
};
export type BrowseTicketsResult = {
max_tickets: number;
tickets: BrowseTicket[];
};
export type DownloadFileParams = FilesParams;
export type DownloadFileResult = string;
export type LoginParams = {
user: string;
password: string;
};
export type LoginResult = {
token: string;
};
export declare enum ReadWriteMode {
Simple = "simple",
Raw = "raw"
}
export type ReadParams = {
var: string;
mode?: ReadWriteMode;
};
export type ReadResult = RPCVarTypeSimple | RPCVarTypeRaw;
export type WriteParams = {
var: string;
mode?: ReadWriteMode;
value: RPCVarTypeSimple | RPCVarTypeRaw;
};
export type WriteResult = boolean;
export type GetCertificateUrlParams = undefined;
export type GetCertificateUrlResult = string;
export type GetPermissionsParams = undefined;
export type GetPermissionsResult = {
name: PlcPermissions;
}[];
export type PingParams = undefined;
export type PingResult = string;
export declare enum RPCErrorCode {
PERMISSON_DENIED = 2,
NO_RESOURCES = 4,
LOGIN_FAILED = 100,
ALREADY_AUTHENTICATED = 101,
PASSWORD_EXPIRED = 102,
ADRESS_NOT_FOUND = 200,
INVALID_ADRESS = 201,
INVALID_ARRAY_INDEX = 203,
UNSUPPORTED_ADRESS = 204
}
export type RPCLoginError = RPCErrorCode.LOGIN_FAILED | RPCErrorCode.ALREADY_AUTHENTICATED | RPCErrorCode.PASSWORD_EXPIRED | true;