Beispiel #1
0
 def from_corp_name(corp_name, corp_assets=None):
     pos_mod_dict = {}
     pos_list = []
     corp_assets = corp_assets or Asset.from_entity_name(corp_name)
     assets = [a for a in corp_assets if Pos.is_pos_mod(a)]
     pos_mods = [m for m in assets if m.group.name != 'Control Tower']
     mod_locations = item_locations([m.item_id for m in pos_mods])
     pos_assets = {
         p.item_id: p
         for p in assets if p.group.name == 'Control Tower'
     }
     pos_locations = item_locations(
         [p.item_id for p in pos_assets.values()])
     for mod in pos_mods:
         mod.xyz = mod_locations[mod.item_id]
         mods = pos_mod_dict.setdefault(nearest(mod.xyz, pos_locations), [])
         mods.append(mod)
     corp_id = name_to_id(corp_name, 'corporation')
     poses_request = esi.op['get_corporations_corporation_id_starbases'](
         corporation_id=corp_id)
     poses_response = esi_client.request(poses_request)
     if not poses_response.status == 200:
         raise HTTPError(poses_response.data['error'])
     poses = {s.starbase_id: s for s in poses_response.data}
     for pos_id, pos in poses.iteritems():
         pos.update(pos_assets[pos.starbase_id].__dict__)
         pos['xyz'] = pos_locations[pos.starbase_id]
         pos_object = Pos.from_id(corp_id=corp_id,
                                  mods=pos_mod_dict.get(pos_id, []),
                                  **pos)
         pos_list.append(pos_object)
     return pos_list
Beispiel #2
0
 def from_corporation(cls, corporation_name, assets=None):
     structure_list = []
     corporation_id = name_to_id(corporation_name, 'corporation')
     assets = assets or Asset.from_entity_id(corporation_id, 'corporations')
     endpoint = 'get_corporations_corporation_id_structures'
     structures_request = esi.op[endpoint](corporation_id=corporation_id)
     structures_response = esi_client.request(structures_request)
     structures = structures_response.data
     endpoint = 'get_corporation_corporation_id_mining_extractions'
     detonations_request = esi.op[endpoint](corporation_id=corporation_id)
     detonations_response = esi_client.request(detonations_request)
     detonations = detonations_response.data
     detonations = {
         d['structure_id']: d['chunk_arrival_time']
         for d in detonations
     }
     structure_keys = [
         'structure_id', 'corporation_id', 'system_id', 'type_id',
         'services', 'fuel_expires', 'state', 'state_timer_end'
     ]
     for s in structures:
         sid = s['structure_id']
         kwargs = {k: v for k, v in s.items() if k in structure_keys}
         kwargs['type_name'] = ids_to_names([s['type_id']])[s['type_id']]
         kwargs['detonation'] = detonations.get(sid)
         structure_contents = [a for a in assets if a.location_id == sid]
         if structure_contents:
             kwargs['fitting'] = Fitting.from_assets(structure_contents)
             kwargs['fuel'] = [
                 a for a in structure_contents
                 if a.location_flag == 'StructureFuel'
             ]
         structure_list.append(cls(**kwargs))
     return structure_list
Beispiel #3
0
def pos_assets():
    corp_id = name_to_id(CORPORATION_NAME, 'corporation')
    asset_xml = xml_api('/corp/AssetList.xml.aspx',
                        params={'corporationID': corp_id},
                        xpath='.//rowset[@name="assets"]/row[@singleton="1"]')
    pos = {}
    mods = {}
    for row in asset_xml:
        typeID = int(row.get('typeID'))
        # Filter out things that aren't POS mods
        if typeID not in pos_mods:
            continue
        # Decorate POS mods with SDE data
        annotate_element(row, pos_mods[typeID])
        itemID = int(row.get('itemID'))
        if row.get('groupName') == 'Control Tower':
            pos_stuff = pos
        else:
            pos_stuff = mods
        pos_stuff[itemID] = row.attrib
        for contents in row.findall('.//rowset[@name="contents"]/row'):
            typeID = int(contents.get('typeID'))
            # Decorate POS mod contents with SDE data
            if typeID in moon_goo:
                annotate_element(contents, moon_goo[typeID])
            elif typeID in fuel_types:
                annotate_element(contents, fuel_types[typeID])
            else:
                continue
            parents_contents = pos_stuff[itemID].setdefault('contents', [])
            parents_contents.append(contents.attrib)
    locations = item_locations(pos.keys() + mods.keys())
    for itemID, location in locations.iteritems():
        try:
            pos[itemID].update(location)
        except KeyError:
            mods[itemID].update(location)
    pos_locations = {i: (pos[i]['x'], pos[i]['y'], pos[i]['z']) for i in pos}
    for i, d in mods.iteritems():
        try:
            location = (d['x'], d['y'], d['z'])
        except KeyError:
            print '{} ({}) has no coordinates'.format(d['typeName'], i)
            continue
        nearest_pos = nearest(location, pos_locations)
        parent_pos_mods = pos[nearest_pos].setdefault('mods', [])
        if d['groupName'] == 'Silo':
            if pos[nearest_pos]['raceName'] == 'Amarr':
                d['capacity'] = Decimal(d['capacity']) * Decimal(1.5)
            if pos[nearest_pos]['raceName'] == 'Gallente':
                d['capacity'] = Decimal(d['capacity']) * Decimal(2)
        parent_pos_mods.append(d)
    return pos
Beispiel #4
0
 def from_corporation(cls, corporation_name, token=access_token, assets={}):
     corporation_id = name_to_id(corporation_name, 'corporation')
     structures = esi_api('Corporation.get_corporations_corporation_id_structures', token=token, corporation_id=corporation_id)
     structure_keys = ['structure_id', 'system_id', 'services', 'fuel_expires']
     
     for s in structures:
         sid = s['structure_id']
         kwargs = {k:v for k,v in s.items() if k in structure_keys}
         kwargs['token'] = token
         if 'children' in assets.get(sid).keys():
             kwargs['fitting'] = Fitting.from_assets(assets[sid]['children'])
             kwargs['structure_type_id'] = assets[sid]['typeID']
             kwargs['structure_type_name'] = assets[sid]['typeName']
         else:
             kwargs['structure_type_id'] = s['type_id']
             kwargs['structure_type_name'] = ids_to_names([s['type_id']])[s['type_id']]
         yield cls(**kwargs)
def check_citadels():
    """
    Check citadels for fuel and services status
    """
    corporation_id = name_to_id(CORPORATION_NAME, 'corporation')
    structures = esi_api(
        'Corporation.get_corporations_corporation_id_structures',
        token=access_token,
        corporation_id=corporation_id)
    detonations = esi_api(
        'Industry.get_corporation_corporation_id_mining_extractions',
        token=access_token,
        corporation_id=corporation_id)
    detonations = {d['structure_id']: d for d in detonations}
    now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
    too_soon = datetime.timedelta(days=TOO_SOON)
    messages = []
    for structure in structures:
        structure_id = structure['structure_id']
        message = []

        # Grab structure name
        try:
            structure_info = esi_api(
                'Universe.get_universe_structures_structure_id',
                token=access_token,
                structure_id=structure_id)
        except HTTPForbidden, e:
            messages.append(
                'Found a citadel ({}) in {} that doesn\'t allow {} to dock!'.
                format(structure_id, structure['system_id'], CORPORATION_NAME))
            continue
        name = structure_info.get('name')

        # List online/offline services
        online_services = []
        offline_services = []
        for service in structure.get('services') or []:
            if service['state'] == 'online':
                online_services.append(service.get('name'))
            if service['state'] == 'offline':
                offline_services.append(service.get('name'))
        online = ', '.join([service for service in online_services])
        offline = ', '.join([service for service in offline_services])

        # Check when fuel expires
        fuel_expires = structure.get('fuel_expires', None)

        # Check for upcoming detonations
        try:
            detonation = detonations[structure_id]['chunk_arrival_time']
            if detonation - now < too_soon:
                message.append('Ready to detonate {}'.format(detonation))
        except KeyError:
            pass

        # Build message for fuel running out and offline services
        if fuel_expires and (fuel_expires - now.date() < too_soon):
            message.append('Runs out of fuel on {}'.format(fuel_expires))
            if online_services:
                message.append('Online Services: {}'.format(online))
            if offline_services:
                message.append('Offline Services: {}'.format(offline))
        elif offline_services:
            message.append('Offline services: {}'.format(offline))
        if message:
            messages.append('\n'.join(['{}'.format(name)] + message))
Beispiel #6
0
def check_pos(corp_name, corp_assets=None):
    """
    Check POS for fuel and status
    
    Returns:
        list: list of alert strings

    """
    messages = []
    corp_id = name_to_id(CONFIG['CORPORATION_NAME'], 'corporation')
    pos_list = Pos.from_corp_name(corp_name, corp_assets)
    if not pos_list:
        return messages
    alliance_id_request = esi.op['get_corporations_corporation_id'](
        corporation_id=corp_id)
    alliance_id = esi_client.request(alliance_id_request).data.get(
        'alliance_id', None)
    sovs = sov_systems(alliance_id)
    for pos in pos_list:
        # TODO: All this could be done in the Pos object for easier testing
        # But POS are going away ;)
        sov = pos.system_id in sovs
        has_stront = False
        has_fuel = False
        has_defensive_mods = False
        for fuel in pos.fuels:
            multiplier = .75 if sov else 1.0
            rate = pos_fuel[pos.type_id][fuel.type_id] * multiplier
            if fuel.type_id == 16275:
                has_stront = True
                if pos.state == 'offline':
                    continue
                reinforce_hours = int(fuel.quantity / rate)
                if reinforce_hours < CONFIG['STRONT_HOURS']:
                    message = '{} has {} hours of stront'.format(
                        pos.moon_name, reinforce_hours)
                    messages.append(message)
            else:
                has_fuel = True
                if pos.state == 'offline':
                    continue
                how_soon = datetime.timedelta(fuel.quantity / (rate * 24))
                if how_soon < CONFIG['TOO_SOON']:
                    days = 'day' if how_soon == 1 else 'days'
                    message = '{} has {} {} of fuel'.format(
                        pos.moon_name, how_soon, days)
                    messages.append(message)
        for mod in pos.mods:
            if mod.group.name == 'Shield Hardening Array':
                has_defensive_mods = True
        if pos.state != 'online':
            if has_fuel and pos.state == 'offline' and not has_defensive_mods:
                continue
            message = '{} is {}'.format(pos.moon_name, pos.state)
            if pos.reinforced_until:
                state_predicates = {'reinforced': 'until'}
                message += ' {} {}'.format(
                    state_predicates.get(pos.state, 'since'),
                    pos.reinforced_until)
            messages.append(message)
    return messages
Beispiel #7
0
#!/usr/bin/env python

from config import CONFIG
from util import notify_slack, name_to_id
from citadels import check_citadels
from pos import check_pos

if __name__ == '__main__':
    CONFIG['CORP_ID'] = name_to_id(CONFIG['CORPORATION_NAME'], 'corporation')
    messages = []
    try:
        messages += check_citadels()
        messages += check_pos()
    except Exception, e:
        if CONFIG['DEBUG']:
            raise
        if e.message:
            messages = [e.message]
        else:
            raise
    if messages:
        messages.insert(
            0, ' Upcoming {} Structure Maintenence Tasks'.format(
                CONFIG['CORPORATION_NAME']))
        notify_slack(sorted(messages))
Beispiel #8
0
def check_pos():
    pos_list_xml = xml_api('/corp/StarbaseList.xml.aspx')
    poses = pos_assets()
    messages = []
    corp_id = name_to_id(CORPORATION_NAME, 'corporation')
    alliance_id = esi_api('Corporation.get_corporations_corporation_id',
                          corporation_id=corp_id).get('alliance_id', None)
    sovs = sov_systems(alliance_id)
    for pos in pos_list_xml.findall('.//rowset[@name="starbases"]/row'):
        pos_id = int(pos.get('itemID'))
        type_id = int(pos.get('typeID'))
        location_id = int(pos.get('locationID'))
        states = ('Unanchored', 'Offline', 'Onlining', 'Reinforced', 'Online')
        state = states[int(pos.get('state'))]
        if state == 'Unanchored':
            print 'POS {} is unanchored, skipping'.format(pos_id)
            continue
        location_name = esi_api('Universe.get_universe_systems_system_id',
                                system_id=location_id).get('name')
        moon_id = int(pos.get('moonID'))
        moon_name = esi_api('Universe.get_universe_moons_moon_id',
                            moon_id=moon_id).get('name')
        sov = location_id in sovs
        poses[pos_id]['locationName'] = location_name
        poses[pos_id]['moonName'] = moon_name
        poses[pos_id]['moonID'] = moon_id
        has_stront = False
        has_fuel = False
        has_defensive_mods = False
        # TODO: handle purposefully offlined POS by checking for fuel
        for fuel in poses[pos_id].get('contents', []):
            fuel_type_id = int(fuel.get('typeID'))
            quantity = int(fuel.get('quantity'))
            multiplier = .75 if sov else 1.0
            rate = pos_fuel[type_id][fuel_type_id] * multiplier
            fuel['hourly_rate'] = rate
            if fuel_type_id == 16275:
                has_stront = True
                if state == 'Offline':
                    continue
                reinforce_hours = int(quantity / rate)
                message = '{} has {} hours of stront'.format(
                    moon_name, reinforce_hours)
                if reinforce_hours < STRONT_HOURS:
                    messages.append(message)
            else:
                has_fuel = True
                if state == 'Offline':
                    continue
                how_soon = int(quantity / (rate * 24))
                days = 'day' if how_soon == 1 else 'days'
                message = '{} has {} {} of fuel'.format(
                    moon_name, how_soon, days)
                if how_soon < TOO_SOON:
                    messages.append(message)
        for mod in poses[pos_id].get('mods', []):
            # Note this is currently only useful for
            # silos that are being filled (e.g. mining),
            # not emptied (e.g. reaction inputt)
            if mod['typeName'] == 'Silo':
                try:
                    goo = mod['contents'][0]
                except KeyError:
                    goo = None
                if goo:
                    capacity = Decimal(mod['capacity'])
                    name = goo['typeName']
                    volume = Decimal(goo['volume'])
                    quantity = int(goo['quantity'])
                    total_volume = volume * quantity
                    rate = volume * 100 * 24
                    remaining_capacity = capacity - total_volume
                    days_remaining = int(remaining_capacity / rate)
                    days = 'day' if days_remaining == 1 else 'days'
                    message = "{} has {} {} of {} capacity left ({} current units)".format(
                        moon_name, days_remaining, days, name, quantity)
                    if days_remaining < TOO_SOON:
                        messages.append(message)
            if mod['groupName'] == 'Shield Hardening Array':
                has_defensive_mods = True
        if state != 'Online':
            if has_fuel and state == 'Offline' and not has_defensive_mods:
                continue
            statetime = pos.get('stateTimestamp')
            message = '{} is {}'.format(moon_name, state)
            if statetime:
                state_predicates = {'Reinforced': 'until'}
                message += ' {} {}'.format(
                    state_predicates.get(state, 'since'), statetime)
            messages.append(message)
    return messages