10. Tracking Asset Details, Maintenance & Warranty Expirations
Automate Equipment Maintenance, Service Contracts, and Warranty Expiration Alerts
The Scenario
Managing equipment maintenance, warranties, and service contracts through spreadsheets leads to missed inspections, voided warranties, and sudden downtime. Whether you are tracking annual service contracts on lab instruments, routine blade/part maintenance in a machine shop, warranty expirations on meeting room AV assets, or calibration schedules for studio cameras, reactive maintenance is costly. This setup centralizes asset metadata and automates expiration alerts so your facility stays fully operational, safe, and compliant.
🔬 Research Labs & Core Facilities (Primary Example)
- Example: Track maintenance contract expiry dates, vendor service agreements, and mandatory calibration schedules for sensitive analytical instruments like mass spectrometers or centrifuges.
🏢 Coworking Spaces & Facility Management
- Example: Monitor warranty expiration dates, HVAC service logs, and maintenance contracts on high-value meeting room assets like smart displays, video conferencing bars, and projector bulbs.
🛠️ Makerspaces & Machine Shops
- Example: Log blade replacement dates, filter changes, motor inspections, and safety certification schedules for heavy machinery like CNC mills, dust extractors, and laser cutters.
🎙️ Media & Production Studios
- Example: Manage equipment health, lens calibration, firmware updates, and protection plan warranties across camera bodies, audio consoles, and lighting grids.
Implementation Steps
- Create Custom Properties: Go to
Administration → Site Settings → Properties, click+ Add Property, and create the required date field: - Maintenance Contract Expiry Date: Set Type to Date. (Actionable metadata used for automated alerts)
- Attach Properties to Resources:
Navigate to Resources → [Resource Name] → Profile → Propertiesand select Add Existing Property to Resource. - Enter Specific Resource Data: Select Maintenance Contract Expiry Date and choose the appropriate expiration date (e.g.,
2026-10-31). - Configure Automated Expiration Alerts: Go to
Administration → Workflows & Rules → Subscriptions → Active → + Create Subscriptionto set up a 30-day alert for the maintenance contract expiry date. - Configure Automated Expiration Alerts: Go to
Administration → Workflows & Rules → Subscriptions → Active → + Create Subscription. - Set the subscription schedule to run daily (every 1 day) to ensure the system continually checks for upcoming expirations.
- Select Run a Script from the subscription task options and paste the script below. Note that the script targets the property named 'Maintenance Contract Expiry Date'; update this value in the script if your custom property uses a different name.
Note: This script scans the Maintenance Contract Expiry Date field across all resources and triggers email notifications for contracts expiring in 30, 7, or 3 days, helping you track both upcoming and urgent renewals.
1def parse_expiry_date(date_str: str | none = None) -> datetime | none:2 if date_str != None:3 parts: list[str] = util.strings.split(s=date_str, separator='-')4 if len(parts) == 3:5 year_val: dec = util.strings.to_decimal(s=parts[0])6 month_val: dec = util.strings.to_decimal(s=parts[1])7 day_val: dec = util.strings.to_decimal(s=parts[2])8 parsed_dt: datetime = datetime.from_date_and_time(year=year_val, month=month_val,9 day=day_val, hour=0, minute=0, second=0)10 return parsed_dt11 return None1213def calc_days_until(expiry_dt: datetime | none = None, now_dt: datetime | none = None) -> dec | none:14 if expiry_dt != None:15 if now_dt != None:16 exp_start: datetime = datetime.start_of(dt=expiry_dt, unit='day')17 today_start: datetime = datetime.start_of(dt=now_dt, unit='day')18 diff_days: dec = datetime.difference(dt1=exp_start, dt2=today_start, as_days=True)19 return diff_days20 return None2122now: datetime = datetime.now()23nl: str = util.strings.newline()2425tracked_tag: str = 'Lab Machines'26resource_ids: list[str] = api.resources.for_tag(tag=tracked_tag)2728items_3_days: list[str] = []29items_7_days: list[str] = []30items_30_days: list[str] = []31all_items: list[str] = []3233for res_id in resource_ids:34 res_info: dict | none = api.resources.from_id(reservable_id=res_id)35 res_name: str = 'Unknown Resource'3637 if res_info != None:38 fetched_name: str | none = util.dicts.get(d=res_info, path='name')39 if fetched_name != None:40 res_name = fetched_name4142 expiry_prop: str | dec | none = api.resources.custom_property(reservable_id=res_id,43 prop_name='Maintenance Contract Expiry Date')4445 if expiry_prop != None:46 if isinstance(expiry_prop, 'str'):47 expiry_dt: datetime | none = parse_expiry_date(date_str=expiry_prop)48 days_remaining: dec | none = calc_days_until(expiry_dt=expiry_dt, now_dt=now)4950 if days_remaining != None:51 if days_remaining == 3:52 line_3: str = '- ' + res_name + ' (Expires: ' + expiry_prop + ')'53 items_3_days = items_3_days + [line_3]54 all_items = all_items + [line_3]55 else:56 if days_remaining == 7:57 line_7: str = '- ' + res_name + ' (Expires: ' + expiry_prop + ')'58 items_7_days = items_7_days + [line_7]59 all_items = all_items + [line_7]60 else:61 if days_remaining == 30:62 line_30: str = '- ' + res_name + ' (Expires: ' + expiry_prop + ')'63 items_30_days = items_30_days + [line_30]64 all_items = all_items + [line_30]6566total_alerts: dec = len(all_items)6768if total_alerts == 0:69 return {'skip': ['SEND_EMAIL']}70else:71 # Individual timeframe lists (defaults to 'None' if empty)72 list_3_day: str = 'None'73 if len(items_3_days) > 0:74 list_3_day = util.strings.join(lst=items_3_days, s=nl)7576 list_7_days: str = 'None'77 if len(items_7_days) > 0:78 list_7_days = util.strings.join(lst=items_7_days, s=nl)7980 list_30_days: str = 'None'81 if len(items_30_days) > 0:82 list_30_days = util.strings.join(lst=items_30_days, s=nl)8384 # Build dynamically grouped sections (omits headers for empty timeframes)85 sections_list: list[str] = []8687 if len(items_3_days) > 0:88 sec_3: str = '**Urgent - Expiring in 3 Days:**' + nl + list_3_day89 sections_list = sections_list + [sec_3]9091 if len(items_7_days) > 0:92 sec_7: str = '**Expiring in 7 Days:**' + nl + list_7_days93 sections_list = sections_list + [sec_7]9495 if len(items_30_days) > 0:96 sec_30: str = '**Expiring in 30 Days:**' + nl + list_30_days97 sections_list = sections_list + [sec_30]9899 double_nl: str = nl + nl100 formatted_sections: str = util.strings.join(lst=sections_list, s=double_nl)101 expiring_resources_list: str = util.strings.join(lst=all_items, s=nl)102103 return {104 'vars': {105 'expiring_sections': formatted_sections,106 }107 }108
8. Set Task ID: Set the Task ID to SCRIPT for the script task.
9. Add Email Notification Task: Add a new subscription task below the script task and select the Send Email task type. Enter the recipient email addresses for anyone who should receive expiry notifications, along with a subject line and body text. Use $expiring_sections in the email body to dynamically pull in the relevant resource details. Here is an example email template you can use:
Hello,
The following resources have maintenance contracts expiring soon:
$expiring_sections
Please review and initiate renewals as needed.
Thanks,
Lab Operations
- Configure Email Task Properties: For the Send Email task, configure the following properties:
Input Script Task ID: SCRIPT
Task ID: SEND_EMAIL
11. Test the Subscription: Run a test subscription to verify that everything is configured correctly. Ensure your resources have upcoming expiry dates that fall within the 30-, 7-, or 3-day notification windows. To test, click Test Tasks For Date and adjust the test date as needed so it aligns with an upcoming expiration date window.
📖 Learn more about Subscriptions
📖 Learn more about Custom Properties
🎬 [ ▶ Watch: Setting Tiered Free Hours and Usage Caps with Rate Scripts]
In this video guide, we walk through centralizing asset details and configuring automated maintenance alerts for facility equipment. The exact same workflow applies to tracking service contract expirations on lab instruments, managing warranty dates for meeting room AV hardware, tracking machine shop maintenance, or scheduling calibration for production studio gear.