Jump to content

Thorsten Vogt

Super Seeqer
  • Posts

    109
  • Joined

  • Last visited

  • Days Won

    38

Everything posted by Thorsten Vogt

  1. Hi Sivaji, actually you can search by ID using either the API/SDK or writing some code in Data Lab. In terms of API/SDK you should try the /items/{id} endpoint: In case an item exists you will get HTTP 200 as status code and details about the item in the response body. If the item does not exist you receive an HTTP 404 status code. In Data Lab you can use spy.search for this. In case of non-existing item spy.search throws an error, therefore I am iterating over the IDs: item_ids = ["FCC9F932-B328-4A7E-9300-A17331519C93", "BF769E50-B93A-4C1A-81FD-326F488CD1E1", "64832183-D97F-4E5C-81A1-C466C494DC3A", "64832183-D97F-4E5C-81A1-C466C494DC6A", "FCC9F932-B328-4A7E-9300-A17331519C91"] item_infos = [] for item_id in item_ids: try: data = spy.search({"ID": item_id}) item_infos.append("Item with ID " + item_id + " exists") except: item_infos.append("Item with ID " + item_id + " does not exist") print (item_infos) Output looks like this: ['Item with ID FCC9F932-B328-4A7E-9300-A17331519C93 exists', 'Item with ID BF769E50-B93A-4C1A-81FD-326F488CD1E1 exists', 'Item with ID 64832183-D97F-4E5C-81A1-C466C494DC3A does not exist', 'Item with ID 64832183-D97F-4E5C-81A1-C466C494DC6A exists', 'Item with ID FCC9F932-B328-4A7E-9300-A17331519C91 does not exist'] Be aware that both methods return all types of items. In case you want to search only for signals or conditions you have to make some adjustments like evaluating the returned data. Hope this helps. Regards, Thorsten
  2. Hi Kenny, you can do this by first calculating the total duration of each capsule using Signal from Condition Tool: Here "Discrete" is used as the interpolation method as interpolated values of the calculated duration between the capsules for further calculations are not needed. Next you can calculate the average duration again using Signal from Condtion: Depending on where you put the value in step 1 the calculated average can change. In the foregoing example I put the value to the start of the capsule therefore only capsules starting in the bounding condition are used for calculation. If necessary, further adjustments must be made with regard to your usecase. Regards, Thorsten
  3. Hi Dylan, you can use the aggregate function for this: $signal.aggregate(average(), ($signal > 90).removeLongerThan(1wk), durationKey()) In this example the average of the signal is calculated whenever its value is above 90 and the result is drawn as a line over the duration of each capsule. You can find more information on the function and its parameters inside formula documentation. Hope this helps. Regards, Thorsten
  4. Hi Yassine, it might be that there are invalid values in this timeframe. You can try to change your formula to $as32.validValues(). This will remove invalid values from the signal and interpolation should work again. If the gap is greater than the max interpolation setting you can use $as32.validValues().setMaxInterpolation(4weeks) which first removes invalid values and then changes the max interpolation of the signal. Regards, Thorsten
  5. Hello Bayu, you may try it this way. I set up a sample in which my forecasted value will exceed the threshold two times in the next 3 days: First step is identifying these periods by using the following formula: ($forecast > $limit).afterStart(0ns) This will create capsules with zero duration as I just need the timestamps for the points in time when the value will be exceed the limit. Next step is creating a new signal with the timestamp as the value: //Iterate over all capsules to create a signal //with the value of the timestamp at start of the capsule $limitExceeded.toSamples($c -> { //Get date of capsule start $date = $c.startKey() //Create sample for signal sample($c.startKey(), $date) }, 1s) Last step is creating the scorecard: In case you may want to display the timestamp in another format you may read this post and adjust the formula in step 2. Hope this helps. Regards, Thorsten
  6. Hi Ben, another option is using the function highpassfilter() as in the following example: $signal.highPassFilter(20min, 2min, 60).abs().agileFilter(2min) The resulting signal can then be used in Value Search to determine the deviations. Regards, Thorsten
  7. Hi Rosa, have you tried keeping just the calculated signal in the list of signals used for the export? Using the OData Feed URL for Excel (I do not have Power BI) just exports 30 values. Regards, Thorsten
  8. Hi Pat, you may use within() fo this. The following example keeps only the portions of the signal where the value of the signal is above 65: Regards, Thorsten
  9. Hi Ingrid, you try to use splice on a scalar, which is available since R51. In lesser versions you can apply splice only on signals, so changing $h to a signal first should resolve the issue: $h.tosignal().splice($l, $lfc) Regards, Thorsten
  10. Hi Aaron, you can use a formula for this. The following example calculates the total duration of all capsules of the operation condition since 06 Mar 2021 up to now. The result is a scalar. $operation.aggregate(totalDuration('h'), capsule('2021-03-06T00:00:00Z', now())) Another option would be creating a condition that can be used in the "Signal from Condition" tool. You have to select an appropriate maximum capsule duration for the condition: condition(30d, capsule('2021-03-06T00:00:00Z', now())) A more dynamic way would be calculating the duration based on the last maintenance. The following formula creates a condition for the times your equipment is running, in case you only have the maintenance capsules. growEnd(30d) extends the capsules to 30 days so you can use it for the current time. As growEnd() extends the capsules to the beginning of the next capsule I use subtract() to remove the maintenance periods from it. $maintenance.inverse().growend(30d).subtract($maintenance) The resulting condition is used inside Signal from Condition Tool: Will this work for you? Regards, Thorsten
  11. In this case you may change the aggregation function from totalized() to delta().
  12. Hi Robin, you can use toCondition() on the Product ID Signal. This will create a condition with capsules each time the value changes. Then you can use Signal from Condition to get the desired values for each capsule. In the following example I calculate the used energy during each compressor stage: Regards, Thorsten
  13. Hi Vladimir, you can add another boundary to the signal. When choosing "Other" as the relation type a dashed line will be added to the display. In case you only want to have the dashed line for the range where the limits are equal you can create another signal for that and chosse this as the boundary: Will this work for you? Regards, Thorsten
  14. Hi Stephanie, yes, there a multiple solutions. I guess the easiest one is using the shifts() function: //Create shift at 05:30 and combine with shift at 17:30 shifts(5.5, 12h).combineWith(shifts(17.5, 12h)) You could also use periods together with move() or a startdate of the initial shift //Create a 12h capsule every 12hs and move to 05:30 / 17:30 periods(12h, 12h).move(5.5h) //Create a 12h capsules every 12hs based on the specified date periods(12h,12h, '2021-01-01T05:30:00+01:00') In order to create just two capsules based on the current date you may use the following formula. As it uses now() the capsules have an uncertain state. //Get timestamp for today and yesterday at midnight $today = now().floorTime(1d) $yesterday = $today - 1d //create capsules condition(12h, capsule($yesterday + 5.5h, $yesterday + 17.5h), capsule($yesterday + 17.5h, $today + 5.5h)) This is what it looks like in Workbench Regards, Thorsten
  15. The API shown above returns the data in JSON format. To create a CSV file you - can write some custom code making use of the Seeq SDKs (here Python) import seeq_sdk as sdk import csv # login prompt definition def get_authenticated_client(api_url): api_client = sdk.ApiClient(api_url) auth_api = sdk.AuthApi(api_client) auth_input = sdk.AuthInputV1() auth_input.username = <username> auth_input.password = <password> auth_input.auth_provider_class = "Auth" auth_input.auth_provider_id = "Seeq" auth_api.login(body=auth_input) return api_client seeq_api_url = 'http://seeqserver:34216/api' seeq_api_client = get_authenticated_client(seeq_api_url) datasourcesApi = sdk.DatasourcesApi(seeq_api_client) output = datasourcesApi.get_items_hosted_by_datasource(id=<id of datasource>, limit=300) with open("C:\\temp\\items.csv", "w", newline='') as csvFile: writer = csv.writer(csvFile) writer.writerow(["Name", "Type"]) for item in output.items: writer.writerow([item.name, item.type]) - take the output from the response body and use 3rd-party tools to convert to csv - use Seeq Data Lab (requires Seeq Data Lab license) data = spy.search({"Datasource Name": "Example Data"}) data.to_csv('items.csv') Regards, Thorsten
  16. Hi Vegini, I guess there are two ways to accomplish this. First one is using Seeq CLI using the command seeq datasource items on the Seeq server. As you can see below you are able to filter for specific datasources you are interested in and also export the results to a .csv file. To get the name, class or id of a datasource you can execute seeq datasource list first to get the desired information to be used for filtering: More information on the CLI can be found here: https://seeq.atlassian.net/wiki/spaces/KB/pages/215384254/Seeq+Server+Command+Line+Interface+CLI The second way would be utilizing the API, for example in a python script. As you see you have to specify the ID of the datasource to get the associated items. The ID of a datasource can be determined by calling the datasources endpoint: Hope this helps. Regards, Thorsten
  17. Hi Mike, by default the size of the tiles reflects the number of assets under the specific asset. In this example, as Cooling Tower 1 has more assets belonging it then Cooling Tower 2, the area of the rectange is bigger: Assets below Cooling Tower 1: Assets below Cooling Tower 2: As you may notice the shape of the rectangles for Area J and K in Cooling Tower 1 is different from the other rectangles, although the size is the same. Resizing the browser circumvents this issue and displays the rectangles all in the same shape: You can override the size of each item individually as described here: Hope this helps. Regards, Thorsten
  18. Hi Robin, as I understood you want to have the sum of the values at ~ 9 am and ~ 3 pm as the value for the batch 22091 NR. Therefore I changed the last formula of my previous post: $batch.removeLongerThan(1wk).tosamples($capsule -> { $maxFirst = $capsulesForCounter.toGroup($capsule).first().property('CounterValue') $sumOfMax = $capsulesForCounter.toGroup($capsule).reduce(0, ($r, $x) -> $r + $x.property('CounterValue')) sample($capsule.startKey(), $sumOfMax-$maxFirst) }, 1d).tostep(1wk) Regards, Thorsten
  19. Hi Robin, you may try the following way. I tried to set up an environment, that represents your data. In the first step I created a condition for each batch: As you can see the "Counter" signal is increasing after the end of the batch. Next I created capsules for the periods between every counter reset using formula. For each capsule the maximum value is stored as a property: ($counter.runningDelta() < 0).afterStart(0s).inverse().removeLongerThan(1wk).transform($c -> $c.setproperty('CounterValue', $counter.maxValue($c))) In the last step I used another formula to transfer the countervalue to a signal that is displayed across the duration of the batch: $batch.removeLongerThan(1wk).tosamples($capsule -> { $max = $capsulesForCounter.toGroup($capsule).last().property('CounterValue') sample($capsule.startKey(), $max) }, 1d).tostep(1wk) Will this work for you? Regards, Thorsten
  20. Hi Bella, you can chain the splice command multiple times: You may also have a look at this post: Hope this helps. Regards, Thorsten
  21. Hello Arnaud, the error is occuring because of the unit of the signal. I guess the unit of your signal is "t" which is converted to "t²" and "t³" for the respective parts of the formula. Therefore they cannot be used in an addition or subtraction. To get the fomula working simply convert the signal to a unitless one before calculating the polynom. The resulting signal is unitless. You can use the setUnits() function to specify a unit if you need one. Hope this helps. Regards, Thorsten
  22. Hi Vladimir, the error indicates that at least one of the conditions used in the formula does not have a maximum capsule duration defined. To get the formula working you have to specify a maximum capsule duration by using removeLongerThan(). The function takes a scalar value (e.g. 1wk) and removes all capsules longer than that duration. $A.removeLongerThan(1wk).transform( $capsule -> $BB.removeLongerThan(1wk).toGroup($capsule).first() ) You can check for a maximum duration by clicking the "i" icon next to the item in Details Pane: If the attribute is missing, the item doesn't have a maximum duration specified. This is the case if you create a condition by using a simple Value Search. Regards, Thorsten.
  23. Hi Vladimir, you may use a transform for this: $A.transform($capsule -> $BB.toGroup($capsule).first()) $A refers to condition A, $BB refers to condition BB. The formula retrieves all capsules of BB during A and returns a condition containing only the first capsule of BB: Hope this helps. Regards, Thorsten
  24. Hi Vladimir, regarding the first question: As I understand your question you want to calcuate the duration of the period when the valve is opened . You can do this by creating a "Value Search" and then using "Signal from Condition" to calculate the duration of each capsule: Regarding your second question: Create a "Periodic Condition" to create capsules for the periods you are interested in. Then create another "Signal from Condition" to count the number of "Valve open" capsules during the created Periodic Condition: Does this answer your questions? Regards, Thorsten
  25. Hi Ethan, you can try this: The formula combines two signals with the property value at start an end of the capsule. By using toStep() the samples are connected and by using within() only the portion of the signal within the condition is kept. Does this work for you? Regards, Thorsten
×
×
  • Create New...