Maximo

 View Only
Expand all | Collapse all

Add Meter Reading via Autoscript

  • 1.  Add Meter Reading via Autoscript

    Posted Fri February 04, 2022 07:25 PM

    I had a request for the following functionality:

    1. Show the primary meter for an asset on the work order, along with the last reading and last reading date (no biggie - )
    2. Add a field that would allow the user to put the current meter reading on the work order itself.
    3. Ensure that the reading goes into the "official" meter readings, i.e. average units are calculated, etc.

     

    I put together the following code, but this is failing on the add().

     

    from psdi.server import MXServer

     

    user =  mbo.getUserInfo()

    mxServer = MXServer.getMXServer()

     

    SQL = "metername = '" + meterName + "' and assetnum = '" + asset + "' and siteid = '" + siteid + "'"

    meterreadingSet = mxServer.getMboSet("MeterReading",user)

    if meterreadingSet.isEmpty():

        logger.debug("No current meter readings.")

    else:

        ct = meterreadingSet.count()

        logger.debug("Meter Reading Set has " + str(ct) + " records.")

        reading = meterreadingSet.add()

     

    I also tried this using an mbo.getMboSet, and a work order relationship, but I get an incompatibility error.

     

    So what am I missing?

     

     

     

     


    #Maximo
    #AssetandFacilitiesManagement


  • 2.  RE: Add Meter Reading via Autoscript

    IBM Champion
    Posted Fri February 04, 2022 08:10 PM
    Edited by System Wed March 22, 2023 11:54 AM
    Hi Shannon, 

    Here is working script to add a new meter reading.  In this case for the Asset 13150, Meter RUNHOURS and a new value of 1234.

    You might want to check out using SqlFormat https://www.sharptree.io/blog/2022/2022-01-31-sql-format/

    You may also want to look into closing your MboSet https://www.sharptree.io/blog/2021/2021-11-22-close-things/

    Let me know if you have any questions.

    from psdi.server import MXServer
    from psdi.mbo import SqlFormat
    
    # userInfo is the implicit variable, if it isn't available in your context you can use mbo.getUserInfo()
    assetMeterSet = MXServer.getMXServer().getMboSet("ASSETMETER", userInfo)
    
    try:
        #  Use the SqlFormat to construct the where clause properly
        sqlf = SqlFormat("metername = :1 and assetnum = :2 and siteid = :3")
    
        sqlf.setObject(1,"ASSETMETER", "METERNAME", "RUNHOURS")
        sqlf.setObject(2,"ASSETMETER", "ASSETNUM", "13150")
        sqlf.setObject(3,"ASSETMETER", "SITEID", "BEDFORD")
        
        assetMeterSet.setWhere(sqlf.format())
        
        if assetMeterSet.isEmpty():
            logger.debug("No current meter readings.")
        else:
            assetMeter = assetMeterSet.getMbo(0)
            assetMeter.setValue("NEWREADING", "1234")
            
            assetMeterSet.save()
        
    finally:
        # Make sure you close your sets to avoid leaks.
        assetMeterSet.close()​


    ------------------------------
    Jason VenHuizen
    https://sharptree.io
    https://opqo.io
    ------------------------------



  • 3.  RE: Add Meter Reading via Autoscript

    Posted Mon February 07, 2022 05:30 PM

    Hi Jason:  would "getMbo(0)" not retrieve the first record in the set, which would then get changed?  i.e. rather than using "mbo.add()"

     

     

     






  • 4.  RE: Add Meter Reading via Autoscript

    Posted Mon February 07, 2022 06:30 PM
    That is correct Shannon. However, notice that we're dealing with the ASSETMETER object here, not the reading object itself. By setting the NEWREADING field and saving the record as Jason suggested, you will be triggering some internal Maximo logic that will take care of adding the right objects into the database with your new reading value.

    ------------------------------
    Gabriel Cesario
    Managing Consultant
    IBM
    Melbourne VIC
    ------------------------------



  • 5.  RE: Add Meter Reading via Autoscript

    IBM Champion
    Posted Mon February 07, 2022 06:39 PM
    The ASSETMETER object has a non persistent attribute named NEWREADING and when you provide a value in that attribute and save the ASSETMETER object it creates a new meter reading.  In the example I am assuming that there is only one ASSETMETER for the provide asset number, meter name, and site id, fetching getting that ASSETMETER object and then setting the new reading.

    If I am not explaining that well enough please let me know and I will try to clarify.

    - Jason

    ------------------------------
    Jason VenHuizen
    https://sharptree.io
    https://opqo.io
    ------------------------------



  • 6.  RE: Add Meter Reading via Autoscript

    Posted Wed February 09, 2022 03:53 PM

    Thanks Jason – I totally missed the fact that you'd changed to the ASSETMTER object.  My apologies.

     

    That makes total sense, since it mirrors the functionality as well.

     

    Much appreciated!

     

     

     

    Shannon

     






  • 7.  RE: Add Meter Reading via Autoscript

    Posted Mon February 14, 2022 02:36 PM

    OK another problem though:  if the user goes into the work order and uses the "Enter Meter Reading" action, there are two transactions that result:

    • Entry into the METERREADING table
    • Entry into the WOMETER table.

     

    The autoscript is re-creating the METERREADING entry, but the WOMETER entry is not being created.

     

    Looking at the literature, the DEPLOYEDMETER / ASSETMETER object has a method to ensure that the WOMETER entry is created, but I'm not sure of the usage.

     

    I think I may need to switch to using the ASSETMETER.addReading() - ??

     

     

     

     






  • 8.  RE: Add Meter Reading via Autoscript

    IBM Champion
    Posted Tue February 15, 2022 09:03 AM
    You should check out the METERDATA non-persistent object. You can populate the ASSETNUM, SITEID, METERNAME, NEWREADING, and WONUM fields on a new record and then call the execute() method on the set.

    ------------------------------
    Alex Walter
    A3J Group
    ------------------------------



  • 9.  RE: Add Meter Reading via Autoscript

    Posted Fri February 18, 2022 02:38 PM

    Hi Alex:  saw this just after I posted my latest, but I'll take a look.

     

    Thanks!

     

     

     

     






  • 10.  RE: Add Meter Reading via Autoscript

    Posted Fri February 18, 2022 02:38 PM

    Further to that:  the script to add the new reading via the NEWREADING non-persistent attribute works fine (thanks again, Jason) is working fine, but I can't get the entry into the WOMETER table.  I'm trying to use the MaintainWOMeter() method, but it consistently gives a null pointer exception.  This makes sense since the documentation says it would if the reading hasn't actually been saved yet, but I'm not sure of usage then.  Can anyone help?

     

     

     

    ##########################################################################################################

    # Author: Shannon Rotz

    # Purpose : When a meter reading is entered into the WORKORDER.METERREADING field, add the reading into the Meter Reading table and the WOMeter table.

    # Creation Date : 2022-01-28

    # Update Date :

    ##########################################################################################################

    from psdi.util.logging import MXLogger

    from psdi.util.logging import MXLoggerFactory

    from psdi.mbo import MboConstants

    from psdi.server import MXServer

    from psdi.mbo import SqlFormat

    #12

     

    logger

    logger = MXLoggerFactory.getLogger("maximo.script")

     

    logger.debug("==================== WO-METERREADING." + launchPoint + ": START =====================")

     

    #19

     

    woReading = mbo.getString("NEWREADING")

    asset = mbo.getString("ASSETNUM")

     

    logger.debug("Asset: " + asset + ".  Reading:  " + str(woReading ) )

     

    #26

    if woReading != None and woReading != '' and asset != None and asset != '':

        user =  mbo.getUserInfo()

        mxServer = MXServer.getMXServer()

        meterName = mbo.getString("PRIMARYMETER.METERNAME")

        siteid = mbo.getString("SITEID")

     

        assetMeterSet = mxServer.getMboSet("ASSETMETER", user)

    #34

        try: # Use the SqlFormat to construct the where clause properly

            sqlf = SqlFormat("metername = :1 and assetnum = :2 and siteid = :3 and active = 1")

            sqlf.setObject(1,"ASSETMETER", "METERNAME", meterName)

            sqlf.setObject(2,"ASSETMETER", "ASSETNUM", asset)

            sqlf.setObject(3,"ASSETMETER", "SITEID",siteid)

            assetMeterSet.setWhere(sqlf.format())

            if assetMeterSet.isEmpty():

                logger.debug("No active meter.")

    #43

            else:

                assetMeter = assetMeterSet.getMbo(0)

                logger.debug("Setting New Reading value to " + str(woReading))

                assetMeter.setValue("NEWREADING",woReading)

                reading = assetMeter.returnReadingForWOMeterProcessing()

                assetMeter.maintainWOMeter(reading)

                assetMeterSet.save()

     

    #67

        finally:

            # Make sure you close your sets to avoid leaks.

            assetMeterSet.close()

     

    logger.debug("==================== WO-METERREADING." + launchPoint + ": END =====================")

     






  • 11.  RE: Add Meter Reading via Autoscript

    Posted Tue February 22, 2022 07:13 PM

    Well, I got really close to solving this.  I couldn't get the usage correct on the AssetMeter.MaintainWOMeter(reading) method.  I realized after a while that it's because there was no work order number passed in my script anywhere.

     

    However, I did get a reading returned using the assetMeter.returnReadingForWOMeterProcessing() method, so I used that in my script.  As I said, I ALMOST worked – but the latest error I'm getting is: 

     

    Owner of WOMeter is not valid. (BMXAA4663) . 

     

    This makes sense, I guess, but I need to get past this.  Any ideas, anyone?  The script so far is:

     

                assetMeter = assetMeterSet.getMbo(0)

                logger.debug("Setting New Reading value to " + str(woReading))

                assetMeter.setValue("NEWREADING",woReading)

                assetMeter.setValue("ISDELTA",False)

                assetMeter.setValue("NEWREADINGDATE",currentDate)

                assetMeter.addReading()

                assetMeterSet.save()

    #53

                reading = assetMeter.returnReadingForWOMeterProcessing()

                if reading is None:

                    logger.debug("No reading returned.")

                else:

                    returnedID = reading.getDouble("METERREADINGID")

                    returnedDate = reading.getDate("READINGDATE")

                    logger.debug("Reading is " + str(returnedID))

    #61

                    woMeterSet = mxServer.getMboSet("WOMETER", user)

                   woMeter = woMeterSet.add()

                    woMeter.setValue("WONUM",wonum)

                    woMeter.setValue("SITEID",siteid)

                    woMeter.setValue("STATUS",wostatus)

                    woMeter.setValue("METERNAME",meterName)

                    woMeter.setValue("METERREADINGID",returnedReading)

                    woMeterSet.save()

    #71

        finally:

            # Make sure you close your sets to avoid leaks.

            assetMeterSet.close()

     

     






  • 12.  RE: Add Meter Reading via Autoscript

    Posted Wed February 23, 2022 07:18 PM

    My final conclusion was that I was being idiotic.  Of course it wasn't passing a work order #, since I was using MXServer() and not a relationship.  Duh.

     

    Final version (apart from wrapping up the error messages properly) is:

     

    from psdi.util.logging import MXLogger

    from psdi.util.logging import MXLoggerFactory

    from psdi.mbo import MboConstants

    #10

     

    logger = MXLoggerFactory.getLogger("maximo.script")

    logger.debug("==================== WO-METERREADING." + launchPoint + ": START =====================")

     

    woReading = mbo.getString("NEWREADING")

    asset = mbo.getString("ASSETNUM")

    logger.debug("Meter Reading:  " + str(woReading ) )

     

    #19

    if woReading != None and woReading != '' and asset != None and asset != '':

        assetMeterSet = mbo.getMboSet("PRIMARYMETER")

     

        try:

            if assetMeterSet.isEmpty():

                logger.debug("No active meter.")

    #26

            elif assetMeterSet.count() > 1:

                errorgroup = 'asset'

                errorkey = 'Cannot determine primary meter.'

     

            else:

                assetMeter = assetMeterSet.getMbo(0)

                logger.debug("Active meter found.  Setting New Reading value to " + str(woReading))

                assetMeter.setValue("NEWREADING",woReading)

                assetMeter.setValue("ISDELTA",False)

                assetMeter.addReading()

    #37

                reading = assetMeter.returnReadingForWOMeterProcessing()

                if reading is None:

                    logger.debug("No reading returned.")

                else:

                    assetMeterSet.save()

                    assetMeter.maintainWOMeter(reading)

     

    #46

        finally:

            # Make sure you close your sets to avoid leaks.

            assetMeterSet.close()

     

    logger.debug("==================== WO-METERREADING." + launchPoint + ": END =====================")

     

     






  • 13.  RE: Add Meter Reading via Autoscript

    Posted Tue October 11, 2022 04:30 PM
    Hi Shannon and everyone else that contributed,

    Thanks for sharing all the knowledge above. I've used it to try doing a very similar thing (creating Meter Readings from auto-script).

    But on the step of creating the reading, I'm getting this error:

    "BMXAA7816E - Operation setValue(double value) is not supported on: Data type=null, Value=29492.76, Object name=ASSETMETER, Attribute name=NEWREADING. Report the error to your system administrator."

    I get the Asset MboSet/Mbo through MXServer, then I get the ASSETMETER through a relationship to the assetMbo. The relevant bits of code are below.

    If anyone can shed some light on why I receive the error, that would be appreciated.
    Thanks!
    Ryan

    assetMeterSet = assetMbo.getMboSet("ASSETMETER")
    #  Use the SqlFormat to construct the where clause properly
    sqlf = SqlFormat("metername = :1 and assetnum = :2 and siteid = :3")
    sqlf.setObject(1,"ASSETMETER", "METERNAME", "ODOM-KM")
    sqlf.setObject(2,"ASSETMETER", "ASSETNUM", assetnum)
    sqlf.setObject(3,"ASSETMETER", "SITEID", "SERVICES")
    assetMeterMbo = assetMeterSet.getMbo(0)
    assetMeterMbo.setValue("NEWREADING", odoreading)
    assetMeterMbo.setValue("ISDELTA", False)
    assetMeterSet.save()​


    ------------------------------
    Ryan Coghlin
    ------------------------------



  • 14.  RE: Add Meter Reading via Autoscript

    Posted Tue October 11, 2022 06:05 PM

    Hi Ryan:  my apologies for not posting the final solution.  Actually I ended up doing 3 different scripts, because I had to cover 3 different events.  It was fairly tricky to do, but I'm confident I have the solution (it's been tested but not implemented yet due to other priorities). 

     

    Here's the final version of the first script.  As you can see, there's a reference to another script running on the Save event.

     

    ##########################################################################################################

    # Author: Shannon Rotz

    # Purpose : When a meter reading is entered into the WORKORDER.METERREADING field (user-defined), validate the reading.

    #                  The reading will be added to the asset's meter history when the work order is saved.

    # Creation Date : 2022-01-28

    # Update Date :

    ##########################################################################################################

    from psdi.util.logging import MXLogger

    from psdi.util.logging import MXLoggerFactory

    from psdi.mbo import MboConstants

    from java.util import Date

    from java.util import Calendar

    from psdi.server import MXServer

     

    logger = MXLoggerFactory.getLogger("maximo.script")

    logger.debug("==================== WO-METERREADING." + launchPoint + ": START =====================")

    #17

    def getHourDiff(timeDiff):

        milliseconds = 1000

        milliminutes = milliseconds * 60

        millihours = milliminutes * 60

        millidays = millihours * 24

     

        daysDiff = timeDiff / millidays

        hoursDiff = timeDiff/millihours

        minDiff = timeDiff / milliminutes

     

        #if(hoursDiff != 0):

       return int(hoursDiff)

    #30

     

    woReading = mbo.getString("NEWREADING")

    asset = mbo.getString("ASSETNUM")

    logger.debug("Meter Reading:  " + str(woReading ) )

     

    #36

    if woReading != None and woReading != '' and asset != None and asset != '':

        assetMeterSet = mbo.getMboSet("PRIMARYMETER")

     

        try:

            if assetMeterSet.isEmpty() or assetMeterSet.count() != 1:

                errorgroup = 'asset'

                errorkey = 'noprimary'

    #44

            else:

                assetMeter = assetMeterSet.getMbo(0)

                logger.debug("Active meter found.")    

                lastReading = assetMeter.getString("LASTREADING")  

                lastReading = lastReading.replace(',','')

                lastReadingDate = assetMeter.getDate("LASTREADINGDATE")

                mUnit = assetMeter.getString("METER.MEASUREUNITID")

                logger.debug("Last reading was " + lastReading + " on " + str(lastReadingDate) + ".")

                logger.debug("Unit of Measure is " + mUnit + ".")

                if float(lastReading) > float(woReading):

                    errorgroup = 'meter'

                    errorkey = 'resetNotAllowed'

    #57

                else:

                    if mUnit == "HOURS" or mUnit == "HOUR":

                        cal=Calendar.getInstance()

                        currentDate = MXServer.getMXServer().getDate()

                        timeDiff = currentDate.getTime() - lastReadingDate.getTime()

                        hoursElapsed = getHourDiff(timeDiff.longValue())

                        logger.debug("Hours since last reading are " + str(hoursElapsed))

                        maxValue = float(lastReading) + hoursElapsed

                        if float(woReading) > maxValue:

                            errorgroup = 'meter'

                            errorkey = 'invalidReading'

     

    #70

        finally:

            # Make sure you close your sets to avoid leaks.

            assetMeterSet.close()

     

    logger.debug("==================== WO-METERREADING." + launchPoint + ": END =====================")

     






  • 15.  RE: Add Meter Reading via Autoscript

    Posted Wed October 12, 2022 01:09 PM
    Thanks again Shannon!

    It looks like my problem was a simple one.

    The NEWREADING attribute of ASSETMETER is type ALN. I was trying to pass in a number.   After I changed to string, it started working.

    assetMeterMbo.setValue("NEWREADING", str(odoreading)) #field is ALN, so string

    - Ryan

    ------------------------------
    Ryan Coghlin
    ------------------------------