def _do_iteration(self): log_info('Starting a new iteration') date = datetime.utcnow() # Update the solution tank state solution_tank_was_full = self.solution_tank_is_full self.solution_tank_is_full = self.solution_tank.is_full() # Volume is unknown and pH sensor can be dry if not self.solution_tank_is_full: raise Exception('Solution tank is empty') # Skip one more iteration to let the pH readings stabilize if not solution_tank_was_full: raise Exception('Solution tank has been empty for a while') temperature, _, ph = drop_uncertainty(*self.ph.get_t_v_ph()) if not in_range(ph, self.valid_ph_range): raise FatalException('Invalid pH: {:~.3gP}'.format(ph)) if not in_range(temperature, self.valid_ph_temperature_range): raise FatalException( 'Invalid pH temperature: {:~.3gP}'.format(temperature)) if hasattr(self, 'temperature'): temperature = self.temperature.get_temperature() supply_tank_volume = drop_uncertainty(self.supply_tank.get_volume()) if not in_range(supply_tank_volume, self.valid_supply_tank_volume_range): raise FatalException('Invalid supply tank volume: {:~.3gP}'.format( supply_tank_volume)) nutrients = self._estimate_nutrients(ph) data = { 'date': date.strftime('%Y-%m-%dT%H:%M:%SZ'), 'temperature_C': '%.1f' % temperature.m_as('degC'), 'pH': '%.2f' % ph.m_as('pH'), 'supply_tank_L': '%.0f' % supply_tank_volume.m_as('L'), 'nutrients_mL': '%.1f' % nutrients.m_as('mL') } retry(lambda: self.database.append(data), 'Database append failed') # Data is already in DB, ignore Thingspeak errors retry(lambda: self.thingspeak.append(data), 'Thingspeak append failed', rethrow=False) # We only add nutrients after their amount was logged to DB self.pump_x.pump(nutrients) self.pump_y.pump(nutrients)
def test_rings(self): sl = {} for addr in self.client.procs: sl[addr] = self.client.GetSuccessorList(addr).server_addrs rings = [list(self.client.procs.keys())[0]] print(rings) print(sl) print(list(self.client.procs.keys())) for _ in range(len(self.client.procs) - 1): rings.append(sl[rings[-1]][0]) print(rings) # test rings correctness self.assertEqual(len(rings), len(self.client.procs)) self.assertEqual(sorted(rings), sorted(self.client.procs.keys())) rings = rings * 3 for i in range(1, self.client.n + 2): self.assertTrue( in_range(self.hash(rings[i - 1]), self.hash(rings[i]), self.hash(rings[i + 1]))) # test successor list correctness for addr in self.client.procs: self.assertEqual(len(sl[addr]), self.client.config['successor_list_len']) for x in sl[addr]: self.assertTrue(x in self.client.procs.keys()) rid = rings.index(addr) self.assertEqual( sl[addr], rings[rid + 1:rid + 1 + self.client.config['successor_list_len']]) # test predecessor correctness p = {} for addr in self.client.procs: p[addr] = self.client.GetPredecessor(addr).server_addr self.assertTrue(p[addr] in self.client.procs.keys()) rid = rings.index(addr) + len(self.client.procs.keys()) self.assertEqual(rings[rid - 1], p[addr]) # test finger table correctness f = {} for addr in self.client.procs: f[addr] = self.client.GetFingers(addr).server_addrs print(addr, f[addr]) self.assertEqual(len(f[addr]), self.client.config['mbits'] + 1) for x in f[addr][1:]: self.assertTrue(x in self.client.procs.keys()) hashed_addr = self.hash(addr) for i in range(1, self.client.config['mbits'] + 1): f_hashed_addr = (hashed_addr+(1 << (i-1)))\ & ((1 << self.client.config['mbits'])-1) rid = rings.index(f[addr][i]) self.assertTrue( in_range(self.hash(rings[rid - 1]), f_hashed_addr, self.hash(rings[rid])) or f_hashed_addr == self.hash(rings[rid]))
def rebuild_subplaylist(self, date_range, aperture_range, shutter_range, focal_range): """Narrow down the selected images in the playlist""" aperture_steps = self.frame.aperture_select.steps shutter_steps = self.frame.shutter_select.steps focal_steps = self.frame.focal_select.steps self.sub_playlist = [self.playlist[ind] for ind in range(len(self.playlist)) if in_range(self.date_vals[ind], date_range) and in_range(aperture_steps.index(self.aperture_vals[ind]), aperture_range) and in_range(shutter_steps.index(self.shutter_vals[ind]), shutter_range) and in_range(focal_steps.index(self.focal_vals[ind]), focal_range)]
def move(self, x, y): if not utils.in_range(self.x, x, .05): if self.x < x: self.x += self.myinc elif self.x > x: self.x -= self.myinc else: self.x = x # --------------------------- if not utils.in_range(self.y, y, .05): if self.y < y: self.y += self.myinc elif self.y > y: self.y -= self.myinc else: self.y = y
def FindSuccessor(self, id): successor = None plen = 0 if in_range(self.hashed_addr, id, self.hashed_successor) or id == self.hashed_successor: successor = self.successor else: nxt_addrs = self.ClosestPrecedingNode(id) mprint('nxt addr', id, nxt_addrs) while len(nxt_addrs): nxt_addr = nxt_addrs[0] nxt_addrs = nxt_addrs[1:] try: with grpc.insecure_channel(nxt_addr) as channel: stub = cpg.chordStub(channel) res = stub.GetSuccessor( cp.GetSuccessorRequest(id=str(id)), timeout=self.config['rpc_timeout']) successor = res.server_addr plen = res.path_length + 1 break except Exception as e: mprint("fs", e) # mprint('get suc', successor) return successor, plen
def Get(self, req, ctx): if self.leave: raise Exception('Leave') return mprint('get', req.key, type(req.id)) key, id = req.key, int(req.id) if self.hashed_predecessor and (in_range(self.hashed_predecessor, id, self.hashed_addr) or id == self.hashed_addr): if key in self.store: return cp.GetResponse(val=self.store[key]['val'], server_addr=self.addr, code=cp.Success) else: return cp.GetResponse(server_addr=self.addr, code=cp.KEY_NOT_EXIST) else: nxt_addr, _ = self.FindSuccessor(id) try: with grpc.insecure_channel(nxt_addr) as channel: stub = cpg.chordStub(channel) return stub.Get(cp.GetRequest(key=req.key, id=str(req.id)), timeout=self.config['rpc_timeout']) except Exception as e: mprint('get', e) return cp.GetResponse(code=cp.Error)
def Put(self, req, ctx): if self.leave: raise Exception('Leave') return key, val, id = req.key, req.val, int(req.id) if self.hashed_predecessor and (in_range(self.hashed_predecessor, id, self.hashed_addr) or id == self.hashed_addr): self.store[key] = {'val': val, 'id': id} with grpc.insecure_channel(self.predecessor) as channel: stub = cpg.chordStub(channel) stub.DirectPut(cp.DirectPutRequest( key=key, id=str(id), val=val, uuid=uuid.uuid4().hex, remaining=self.config['max_failures']), timeout=self.config['rpc_timeout'] * self.config['max_failures']) return cp.PutResponse(code=cp.Success) else: nxt_addr, _ = self.FindSuccessor(id) try: with grpc.insecure_channel(nxt_addr) as channel: stub = cpg.chordStub(channel) return stub.Put(cp.PutRequest(key=req.key, val=req.val, id=str(req.id)), timeout=self.config['rpc_timeout']) except Exception as e: mprint('put', e) return cp.PutResponse(code=cp.Error)
def DeleteRange(self, req, ctx): if self.leave: raise Exception('Leave') return from_id, to_id = int(req.from_id), int(req.to_id) for k in list(self.store.keys()): id = self.store[k]['id'] if id == from_id or id == to_id or in_range(from_id, id, to_id): del self.store[k] return cp.DeleteRangeResponse()
def ClosestPrecedingNode(self, id): res = [] for i in range(self.config['mbits'], 0, -1): if self.fingers[i] and in_range( self.hashed_addr, self.fingers[i]['hashed_addr'], id): if self.fingers[i]['addr'] not in res: res.append(self.fingers[i]['addr']) for x in self.successor_list: if x and x not in res: res.append(x) return res
def GetRange(self, req, ctx): if self.leave: raise Exception('Leave') return from_id, to_id = int(req.from_id), int(req.to_id) keys, vals = [], [] for k in self.store.keys(): id = self.store[k]['id'] if id == from_id or id == to_id or in_range(from_id, id, to_id): keys.append(k) vals.append(self.store[k]['val']) return cp.GetRangeResponse(keys=keys, vals=vals)
def Stabilize(self): mprint('stable') try: x = None while self.successor_list[0]: self.successor = self.successor_list[0] self.hashed_successor = self.hash(self.successor) mprint('stable', self.successor) try: if self.addr != self.successor: with grpc.insecure_channel(self.successor) as channel: stub = cpg.chordStub(channel) res = stub.GetPredecessor( cp.Null(), timeout=self.config['rpc_timeout']) mprint('pred', self.successor, res) x = res.server_addr else: x = self.predecessor break except Exception as e: self.successor_list = self.successor_list[1:] + [None] mprint('s1', e, self.successor_list) if x: hashed_x = self.hash(x) if in_range(self.hashed_addr, hashed_x, self.hashed_successor): self.successor = x self.hashed_successor = self.hash(self.successor) self.successor_list = [self.successor ] + self.successor_list[:-1] print('update sl', self.successor_list) self.successor = self.successor_list[0] if self.addr != self.successor: with grpc.insecure_channel(self.successor) as channel: stub = cpg.chordStub(channel) res = stub.Notify(cp.NotifyRequest(server_addr=self.addr), timeout=self.config['rpc_timeout']) res = stub.GetSuccessorList( cp.Null(), timeout=self.config['rpc_timeout']) self.successor_list = [self.successor ] + res.server_addrs[:-1] else: self._Notify(self.addr) except Exception as e: import traceback as tb mprint('s2', self.successor_list, e, tb.format_stack()) pass
def _Notify(self, addr): hashed_addr = self.hash(addr) # mprint("not", addr) if self.predecessor == None or in_range(self.hashed_predecessor, hashed_addr, self.hashed_addr): self.predecessor = addr self.hashed_predecessor = hashed_addr with grpc.insecure_channel(self.predecessor) as channel: stub = cpg.chordStub(channel) res = stub.GetRange( cp.GetRangeRequest( from_id=str((self.hashed_predecessor + 1) & ((1 << self.config['mbits']) - 1)), to_id=str(self.hashed_addr))) for k, v in zip(res.keys, res.vals): self.store[k] = {'val': v, 'id': self.hash(k)} self._DoReplicate(self.config['max_failures'], uuid.uuid4().hex)
def test_find_successor(self): sl = {} for addr in self.client.procs: sl[addr] = self.client.GetSuccessorList(addr).server_addrs rings = [list(self.client.procs.keys())[0]] for _ in range(len(self.client.procs) - 1): rings.append(sl[rings[-1]][0]) print(rings) for i in range(1000): hi = self.hash(str(i)) n = { self.client.Get(addr, str(i)).server_addr for addr in self.client.procs } self.assertEqual(len(n), 1) n = list(n)[0] hn = self.hash(n) p = self.client.GetPredecessor(n).server_addr hp = self.hash(p) self.assertTrue(in_range(hp, hi, hn) or hn == hi)
def get_large_baseline(self): """Creates the large random baseline.""" base_nodes = np.array([[5, 5], [5, 7], [3, 4]]) num_unknown_nodes = 100 sensor_range = 25, size_of_square = 100 seed = 1337 np.random.seed(1337) self.N = num_unknown_nodes self.base = base_nodes (self.B, _) = base_nodes.shape self.x_true = np.random.uniform(size=(self.N, 2)) * size_of_square self.nodes = np.concatenate((self.base, self.x_true)) self._base_map = np.concatenate((np.ones((self.B)), np.zeros(self.N))) self.node_true_dist_mat = cross_distance(self.nodes) self.in_range_mat = in_range(self.node_true_dist_mat, sensor_range) return self
def Own(self, id): return in_range(self.hashed_predecessor, id, self.hashed_addr) or id == self.hashed_addr