def send_decision(self, queue, consumption): sellbuy = "buys" if consumption > 0 else "sells" cprint( self, f"[{self.id}] It is I (home {self.id}) who {sellbuy} {abs(consumption)}J to market" ) queue.send(message=str(consumption), type=comm_utils.market_transfer_id(self.id))
def send_energy(self, queue, destination, count): cprint( self, f"[{self.id}] It is I (home {self.id}) who sends {count}J to home {destination} at slot {comm_utils.energy_transfer_id(destination)}" ) comm_utils.send_energy(queue=queue, amount=count, destination=destination) self.policy.given += count
def special_weather_things(self, infos): if infos is None: return print(f"[{self.id}] {infos}") if infos["Temperature"] < 0: cprint( self, f"[{self.id}] Temperature => consumption : {self.policy.consumption} -> {self.policy.consumption * 2}" ) self.policy.consumption *= 2
def always_sell_excess_behaviour(owner, marketQ, homesQ): balance = owner.policy.current_balance() if balance >= 0: cprint(owner, f"[{owner.id}][always_sell] => i have a positive balance of {balance}, imma sell") return True, balance else: cprint(owner, f"[{owner.id}][always_sell] => in need of {-balance} energy, requesting it") comm_utils.request_energy(owner=owner, queue=homesQ, amount=-balance) # if balance isnt positive we can still try to get energy from others return False, owner.policy.current_balance()
def fulfill_some_request_sub_behaviour(owner, queue, block=False): cprint(owner, f"[{owner.id}][fulfill_requests] -> tryna fulfill some requests") message, id = comm_utils.get_some_energy_request(queue=queue, block=block) # check for energy requests if None not in (message, id): asked = float(message) sent = min(asked, owner.policy.current_balance() ) # give the max we can without being in deficit cprint( owner, f"[{owner.id}][fulfill_requests] => {id - 1} asked for {asked} energy, imma give u {sent} bro" ) if sent > 0: # asked > 0 so if sent < 0 it means we are in deficit and we dont wanna get more debts owner.send_energy( queue=queue, destination=comm_utils.inverse_energy_request_id(id), count=sent) else: # cprint(owner, f"[{owner.id}][fulfill_requests] => aint no requests for me to fulfill imma keep my energy") pass
def run(self): cprint(self, f"[{self.id}] hi from house #{self.id}") # open needed queues market_queue = sysv_ipc.MessageQueue(key=self.market_queue_key) homes_queue = sysv_ipc.MessageQueue(key=self.homes_queue_key) last_market_infos = None while True: # TODO maybe migrate home from thread to process and multithread home so that # TODO-bis exchanges and communication are done in parallel self.special_weather_things( infos=last_market_infos ) # special actions to take in regards to current market state # trading energy with homes until market asks us for an decision result, infos = self.policy.execute( owner=self, comm=(market_queue, homes_queue)) # blocking op # result is how much the home wants to buy/sell, if result > 0 we sell or else we buy if result is None: # just in case result = self.policy.last_decision if infos is not None: try: last_market_infos = json.loads(infos) except Exception: pass # tell the market how much we want self.send_decision( queue=market_queue, consumption=-result ) # blocking # take opposite of decision bc for market negative consumption is selling self.policy.reset( ) # reset production / consumption / given energy / received energy state for next tick sleep(self.interval)
def sell_if_no_takers_behaviour(owner, marketQ, homesQ): balance = owner.policy.current_balance() if balance == 0: cprint( owner, f"[{owner.id}][no_takers->sell] => i have exactly 0 energy left, i'm done" ) return True, balance elif balance > 0: # if we have a surplus of energy we sell it cprint( owner, f"[{owner.id}][no_takers->sell] => i have {balance} excess, i'm tryna give sum" ) fulfill_some_request_sub_behaviour(owner, homesQ, block=False) else: # when in need of energy cprint( owner, f"[{owner.id}][no_takers->sell] => im thirsty for energy, gimme {-balance} pls" ) comm_utils.request_energy(owner=owner, queue=homesQ, amount=-balance) # -balance bc balance < 0 return False, owner.policy.current_balance()
def execute(self, owner, comm): marketQ = comm[0] homesQ = comm[1] # timeout system decision = None market_msg = None start = time.time() while (time.time() - start) < owner.slot_timeout: if market_msg is None: # if market hasn't contacted us yet # check if we have a msg from market market_msg = comm_utils.get_last_message( queue=marketQ, type_id=comm_utils.market_request_id(owner.id)) # we store the last time we checked and we didn't have a message, this reset the timeout if market_msg is None: start = time.time() cprint( owner, f"[{owner.id}][policy] -> still no msg... {market_msg}" ) else: cprint( owner, f"[{owner.id}][policy] -> msg from market !!!! {market_msg} starting slot timeout" ) # accept energy transfers if owner.policy.has_pending_request: comm_utils.accept_energy_transfers_if_any(owner=owner, queue=homesQ) # heuristic/behaviour returns (done, value) decision = self.behaviour(owner, marketQ=marketQ, homesQ=homesQ) if decision[0]: # if done self.last_decision = decision[1] cprint(owner, f"[{owner.id}][policy] => i'm done!") break # sleep the required interval or less to answer the market's request in time time_left = abs(owner.slot_timeout - (time.time() - start)) time.sleep( owner.interval if owner.interval < time_left else time_left) cprint(owner, f"[{owner.id}][policy] -> bitch i'm out") # just in case if self.has_pending_request: comm_utils.cancel_request( owner=owner, queue=homesQ ) # protects ourselves from receiving new energy transfers comm_utils.accept_energy_transfers_if_any(owner=owner, queue=homesQ) # if we're done without being contacted by market we wait for it if market_msg is None: cprint( owner, f"[{owner.id}][policy] waiting on mailbox {comm_utils.market_request_id(owner.id)}" ) market_msg = comm_utils.get_last_message( queue=marketQ, type_id=comm_utils.market_request_id(owner.id), block=True) # blocking cprint(owner, f"[{owner.id}][policy] -> market told me '{market_msg}'") return decision[1], market_msg