Exemplo n.º 1
0
def EventHandler(eventId, eventArg):
    global owm, apiKey, location
    if eventId == events.ids.HOURS: # Get weather once/hour
        if owm == None:
            apiKey = config.Get("owmApiKey")
            location =  config.Get("owmLocation")
        if (apiKey != None and location != None):
            owm = pyowm.OWM(apiKey) # My API key
            try:
                obs = owm.weather_at_place(location)  # My location
            except:
                database.NewEvent(0, "Weather Feed failed!")
                synopsis.problem("Weather", "Feed failed @ " + str(datetime.now()))
                return
            w = obs.get_weather()
            cloudCover = w.get_clouds() # Percentage cloud cover
            variables.Set("cloudCover", str(cloudCover), True)
            outsideTemp = w.get_temperature("celsius")["temp"] # Outside temperature in celsius
            variables.Set("outsideTemperature", str(outsideTemp), True)
            windSpeed = w.get_wind()["speed"]
            variables.Set("windSpeed", str(windSpeed), True)
            rain = w.get_rain()
            if rain != {}:
                rain = 1    # was rain["3h"]   # Rain volume in last 3 hours.  Unknown units, may be ml(?)
            else:
                rain = 0    # No rain
            variables.Set("rain", str(rain), True)
            snow = w.get_snow()
            if snow != {}:
                snow = 1    # was snow["3h"]   # Snow volume in last 3 hours.  Unknown units, may be ml(?)
            else:
                snow = 0    # No snow
            variables.Set("snow", str(snow), True)
            database.NewEvent(0, "Weather now "+str(cloudCover)+"% cloudy")
            events.Issue(events.ids.WEATHER)    # Tell system that we have a new weather report
Exemplo n.º 2
0
 def testConfig(self):
     """Tests storage of simple and structured values in Config entities."""
     self.assertEquals(None, config.Get('k'))
     config.Set('k', 'value')
     self.assertEquals('value', config.Get('k'))
     config.Set('j', False)
     self.assertEquals({'k': 'value', 'j': False}, config.GetAll())
     config.Set('k', [3, 4, {'a': 'b'}, None])
     self.assertEquals([3, 4, {'a': 'b'}, None], config.Get('k'))
     config.Delete('k')
     self.assertEquals(None, config.Get('k'))
Exemplo n.º 3
0
def EventHandler(eventId, eventArg):
    global overrideTimeoutMins, currentTargetTemp
    if eventId == events.ids.MINUTES:
        name = config.Get("HeatingDevice")
        if name != None:
            heatingDevKey = devices.FindDev(
                name
            )  # Get heating device every minute to allow for it changing
            if heatingDevKey != None:  # Check that we have a real heating device
                schedule = config.Get("HeatingSchedule")
                if schedule != None:
                    scheduledTargetTemp = GetTarget(schedule)
                    if scheduledTargetTemp != None:  # We now have a heating device and a schedule to follow or override
                        if overrideTimeoutMins > 0:
                            overrideTimeoutMins = overrideTimeoutMins - 1
                            if overrideTimeoutMins <= 0:  # Just finished override
                                database.NewEvent(
                                    heatingDevKey,
                                    "Resume " + str(scheduledTargetTemp) +
                                    "'C")  # For ActivityLog on web page
                                currentTargetTemp = heating.SetTargetTemp(
                                    heatingDevKey, scheduledTargetTemp
                                )  # Resume schedule here
                            else:  # Still overriding
                                if scheduledTargetTemp != currentTargetTemp:  # Check whether schedule in heating device is about to change target
                                    database.NewEvent(
                                        heatingDevKey,
                                        "Overriding scheduled " +
                                        str(scheduledTargetTemp) + "'C with " +
                                        str(currentTargetTemp) +
                                        "C")  # For ActivityLog on web page
                                    # Un-indent following line to force override temp once/min while overriding, rather than just at change
                                    heating.SetTargetTemp(
                                        heatingDevKey, currentTargetTemp
                                    )  # Re-Set target in heating device (since it's also running the schedule)
                        else:  # Not overriding
                            if scheduledTargetTemp != currentTargetTemp:
                                database.NewEvent(
                                    heatingDevKey,
                                    "Scheduled " + str(scheduledTargetTemp) +
                                    "'C")  # For ActivityLog on web page
                                #heating.SetTargetTemp(heatingDevKey, scheduledTargetTemp)   # Set target in heating device here.  (Not needed since it's running the schedule directly)
                                currentTargetTemp = scheduledTargetTemp
                    # else: No scheduled target
                # else: No HeatingSchedule
            # else: Despite having a name, there's no associated device
            variables.Set("TargetTemp", str(currentTargetTemp))
        else:  # Ignore schedules and overrides if no named heating device
            synopsis.problem(
                "NoHeatingDevice",
                "No HeatingDevice entry in config, needed to resume after override"
            )
Exemplo n.º 4
0
def UpdateMetadata(address):
    """Updates the cached metadata dictionary for a single source."""
    if config.Get('metadata_max_megabytes_per_day_per_source', 50) == 0:
        logging.info('Skipped; metadata_max_megabytes_per_day_per_source is 0')
        return
    fetch_time = time.time()
    metadata = METADATA_CACHE.Get(address)
    metadata = FetchAndUpdateMetadata(metadata, address)
    metadata['fetch_time'] = fetch_time
    METADATA_CACHE.Set(address, metadata)
    logging.info('Updated metadata for source: %s %r', address, metadata)
    if config.Get('metadata_fetch_log'):
        MetadataFetchLog.Log(address, metadata)
Exemplo n.º 5
0
  def Get(self, label, domain=None):  # pylint: disable=g-bad-name
    """Displays a published map by its domain and publication label."""
    domain = domain or config.Get('primary_domain') or ''
    entry = model.CatalogEntry.Get(domain, label)
    if not entry:
      # Fall back to the map list for users that go to /crisismap/maps.
      # TODO(kpy): Remove this when the UI has a way to get to the map list.
      if label == 'maps':
        return self.redirect('.maps')
      raise base_handler.Error(404, 'Label %s/%s not found.' % (domain, label))

    cm_config = GetConfig(self.request, catalog_entry=entry,
                          xsrf_token=self.xsrf_token)
    map_root = cm_config.get('map_root', {})
    # SECURITY NOTE: cm_config_json is assumed to be safe JSON, and head_html
    # is assumed to be safe HTML; all other template variables are autoescaped.
    # Below, we use cm_config.pop() for template variables that aren't part of
    # the API understood by google.cm.Map() and don't need to stay in cm_config.
    self.response.out.write(self.RenderTemplate('map.html', {
        'maps_api_url': cm_config.pop('maps_api_url', ''),
        'head_html': cm_config.pop('custom_head_html', ''),
        'lang': cm_config['lang'],
        'lang_lower': cm_config['lang'].lower().replace('-', '_'),
        'json_proxy_url': cm_config['json_proxy_url'],
        'maproot_url': cm_config.pop('maproot_url', ''),
        'map_title': map_root.get('title', '') + ' | Google Crisis Map',
        'map_description': ToPlainText(map_root.get('description')),
        'map_url': self.request.path_url,
        'map_image': map_root.get('thumbnail_url', ''),
        'cm_config_json': base_handler.ToHtmlSafeJson(cm_config)
    }))
Exemplo n.º 6
0
    def RenderTemplate(self, template_name, context):
        """Renders a template from the templates/ directory.

    Args:
      template_name: A string, the filename of the template to render.
      context: An optional dictionary of template variables.  A few variables
          are automatically added to this context:
            - {{root}} is the root_path of the app
            - {{user}} is the signed-in user
            - {{login_url}} is a URL to a sign-in page
            - {{logout_url}} is a URL that signs the user out
            - {{navbar}} contains variables used by the navigation sidebar
    Returns:
      A string, the rendered template.
    """
        path = os.path.join(os.path.dirname(__file__), 'templates',
                            template_name)
        root = config.Get('root_path') or ''
        user = users.GetCurrent()
        context = dict(context,
                       root=root,
                       user=user,
                       xsrf_tag=self.xsrf_tag,
                       login_url=users.GetLoginUrl(self.request.url),
                       logout_url=users.GetLogoutUrl(root + '/.maps'),
                       navbar=self._GetNavbarContext(user))
        return template.render(path, context)
Exemplo n.º 7
0
def GetMapPickerItems(domain, root_path):
  """Fetches the list of maps to show in the map picker menu for a given domain.

  Args:
    domain: A string, the domain whose catalog to fetch.
    root_path: The relative path to the Crisis Map site root.

  Returns:
    A list of {'title': ..., 'url': ...} dictionaries describing menu items
    corresponding to the CatalogEntry entities for the specified domain.
  """
  map_picker_items = []

  # Add menu items for the CatalogEntry entities that are marked 'listed'.
  if domain:
    if domain == config.Get('primary_domain'):
      map_picker_items = [
          {'title': entry.title, 'url': root_path + '/' + entry.label}
          for entry in list(model.CatalogEntry.GetListed(domain))]
    else:
      map_picker_items = [
          {'title': entry.title,
           'url': root_path + '/%s/%s' % (entry.domain, entry.label)}
          for entry in list(model.CatalogEntry.GetListed(domain))]

  # Return all the menu items sorted by title.
  return sorted(map_picker_items, key=lambda m: m['title'])
Exemplo n.º 8
0
def GetPlacesApiResults(base_url, request_params, result_key_name=None):
    """Fetches results from Places API given base_url and request params.

  Args:
    base_url: URL prefix to use before the request params
    request_params: An array of key and value pairs for the request
    result_key_name: Name of the results field in the Places API response
        or None if the whole response should be returned
  Returns:
    Value for the result_key_name in the Places API response or all of the
    response if result_key_name is None
  """
    google_api_server_key = config.Get('google_api_server_key')
    if not google_api_server_key:
        raise base_handler.Error(
            500, 'google_api_server_key is not set in the config')
    request_params += [('key', google_api_server_key)]
    url = base_url + urllib.urlencode([(k, v) for k, v in request_params if v])

    # Call Places API if cache doesn't have a corresponding entry for the url
    def GetPlacesJson():
        response = urlfetch.fetch(url=url, deadline=DEADLINE)
        return json.loads(response.content)

    response_content = JSON_PLACES_API_CACHE.Get(url, GetPlacesJson)

    # Parse results
    status = response_content.get('status')
    if status != 'OK' and status != 'ZERO_RESULTS':
        # Something went wrong with the request, log the error
        logging.error('Places API request [%s] failed with error %s', url,
                      status)
        return []
    return (response_content.get(result_key_name)
            if result_key_name else response_content)
Exemplo n.º 9
0
def SetSunTimes():
    cityName = config.Get("cityName")
    if cityName != None:
        city = LocationInfo(cityName)
        s = sun(city.observer, date=datetime.now())
        variables.Set("dawn", str(s['dawn'].strftime("%H:%M")), True)
        variables.Set("sunrise", str(s['sunrise'].strftime("%H:%M")), True)
        variables.Set("sunset", str(s['sunset'].strftime("%H:%M")), True)
        variables.Set("dusk", str(s['dusk'].strftime("%H:%M")), True)
Exemplo n.º 10
0
 def CheckAccess(self):
     """If login_access_list is set, accept only the specified logins."""
     login_access_list = config.Get('login_access_list')
     if login_access_list is not None:
         user = users.GetCurrent()
         if not user:
             raise RedirectToUrl(users.GetLoginUrl(self.request.url))
         if user.email not in login_access_list:
             raise perms.AuthorizationError(user, None, None)
Exemplo n.º 11
0
 def Get(self, label, topic_id, user=None, domain=None):
     domain = domain or config.Get('primary_domain') or ''
     entry = model.CatalogEntry.Get(domain, label)
     if not entry:
         logging.severe('No map with label %s under domain %s' %
                        (label, domain))
         raise base_handler.Error(404, 'No such map.')
     self.GetForMap(entry.map_root, entry.map_version_id, topic_id, label,
                    domain)
Exemplo n.º 12
0
 def Get(self, label, user=None, domain=None):
   domain = domain or config.Get('primary_domain') or ''
   entry = model.CatalogEntry.Get(domain, label)
   if not entry:
     raise base_handler.Error(404, 'No such map.')
   topics = entry.map_root.get('topics', [])
   if not topics:
     raise base_handler.Error(404, 'Map has no topics.')
   self.redirect('%s/%s' % (label, str(topics[0]['id'])))
Exemplo n.º 13
0
def MakeText(id):
    if weather.forecastPeriod=="": return None;
    reportDict = dict()
    reportDict["target"] = id
    minutes = datetime.now().minute
    #if minutes % 2 == 0:
    #    reportDict["display"] = "off"
    #else:
    reportDict["display"] = "on" # For now at least
    reportDict["period"] = weather.forecastPeriod
    reportDict["icon"] = str(weather.symSym)[4:]
    reportDict["cloudText"] = weather.cloudText
    reportDict["maxTemp"] = str(round(weather.maxTemp))+"C"
    reportDict["minTemp"] = str(round(weather.minTemp))+"C"
    reportDict["windSpeed"] = str(round(weather.maxWind))
    reportDict["windDir"] = str(weather.windDir)
    reportDict["windText"] = weather.windText
    now = datetime.now()
    reportDict["timeDigits"] = str(now.strftime("%H:%M"))
    reportDict["timeText"] = GetTimeInWords()
    reportDict["dayOfWeekText"] = str(now.strftime("%A"))
    reportDict["dayOfMonthText"] = str(int(now.strftime("%d"))) # Use int() to remove leading zero
    reportDict["monthText"] = str(now.strftime("%B"))
    powerMonitorName = config.Get("PowerMonitor") # House power monitoring device
    if powerMonitorName != None:
        devKey = devices.FindDev(powerMonitorName)
        if devKey != None:
            powerW = database.GetLatestLoggedItem(devKey, "PowerReadingW")
            if powerW != None:
                reportDict["powerNow"] = str(powerW[0])
    energyToday = variables.Get("energyToday_kWh")
    if energyToday:
        reportDict["energyToday"] = energyToday
    tempMonitorName = config.Get("HouseTempDevice") # House temperature monitoring device
    if tempMonitorName != None:
        devKey = devices.FindDev(tempMonitorName)
        if devKey != None:
            houseTemp = database.GetLatestLoggedItem(devKey, "TemperatureCelsius")
            reportDict["houseTemp"] = '%.1f' % (houseTemp[0])
    targetTemp = variables.Get("TargetTemp")
    if targetTemp != None:
        reportDict["TargetTemp"] = targetTemp
    #log.debug("ReportDict for:" +id + "=" + str(reportDict)) # Already reported in WiFiServer.py
    return (str(reportDict))
Exemplo n.º 14
0
def DetermineFetchInterval(metadata):
    """Decides how long to wait before fetching a layer's data again."""
    # TODO(kpy): Add overall rate-limiting (total bandwidth across all sources).
    # By default, fetch each source at most once per minute.
    min_interval = config.Get('metadata_min_interval_seconds', 60)
    # By default, on failure, wait at least 10 minutes before trying again.
    min_interval_after_error = config.Get(
        'metadata_min_interval_after_error_seconds', 600)
    # By default, fetch each source at least once a day.
    max_interval = config.Get('metadata_max_interval_hours', 24) * 3600
    # By default, limit fetch bandwidth to 50 megabytes per day per source.
    mb_per_day = config.Get('metadata_max_megabytes_per_day_per_source', 50)

    # Estimate interval based on a metric of cost expended by the remote server.
    fetch_cost = HTTP_FIXED_COST + metadata.get('fetch_length', 0)
    interval = int(fetch_cost / (max(mb_per_day, 0.001) * 1e6 / 24 / 3600))

    # Also keep the interval within our minimum and maximum bounds.
    min_seconds = (metadata.get('fetch_error_occurred')
                   and min_interval_after_error or min_interval)
    return max(min_seconds, min(max_interval, interval))
Exemplo n.º 15
0
def ScheduleFetch(address, countdown=None):
    """Schedules the next fetch task for a source."""
    metadata = METADATA_CACHE.Get(address) or {}
    if not metadata.get('fetch_impossible'):
        if countdown is None:
            countdown = DetermineFetchInterval(metadata)
        logging.info('Scheduling fetch in %ds for source: %s', countdown,
                     address)
        taskqueue.add(queue_name='metadata',
                      countdown=countdown,
                      method='GET',
                      url=(config.Get('root_path') or '') + '/.metadata_fetch',
                      params={'source': address})
Exemplo n.º 16
0
def EventHandler(eventId, eventArg):
    global ser, txBuf, rxBuf
    if eventId == events.ids.INIT:
        serPort = config.Get("tty", '/dev/ttyUSB0')
        serSpeed = config.Get("baud", '19200')
        ser = serial.Serial(serPort, int(serSpeed), timeout=0)
        ser.flushInput()
        if database.GetDevicesCount()==0: # If we have no devices yet, then...
            devices.Add("0000", "N/A", "COO") # ...make sure we add this device as the first item before we try to use it!
        queue.EnqueueCmd(0, ["ATS63=0007", "OK"]) # Request RSSI & LQI on every received message, also disable automatic checkIn responses
        queue.EnqueueCmd(0, ["ATS0F=0400", "OK"]) # Use 0600 to set bit 9 (bit 10 already set) to get rawzcl responses so we can see schedule responses from thermostat
        if database.GetDeviceItem(0, "modelName") == None:
            queue.EnqueueCmd(0, ["ATI", "OK"]) # Request our EUI, as well as our Telegesis version
        queue.EnqueueCmd(0, ["AT+N", "OK"]) # Get network information, to see whether to start new network or use existing one
    elif eventId == events.ids.SECONDS:
        HandleSerial(ser)
        while len(rxBuf):
            Parse(rxBuf.popleft())
    elif eventId == events.ids.RADIO_INFO:
        print(ourChannel+","+ourPowLvl+","+ourPan+","+ourExtPan) # Formatted to make it easy to extract in php
    elif eventId == events.ids.INFO:
        print("TxBuf: ", str(txBuf))
Exemplo n.º 17
0
def ContainsSpam(text):
  """Checks text for words and phrases that are considered spam.

  Args:
    text: The text to be scanned.

  Returns:
    True if the text contains any of the words or phrases in the config setting
    'crowd_report_spam_phrases', which should be a list of strings.  Whitespace
    is normalized and case is ignored for comparison.
  """
  lowercase_text = ' '.join(text.lower().split())
  for spam_phrase in config.Get('crowd_report_spam_phrases', []):
    lowercase_spam = ' '.join(spam_phrase.lower().split())
    if lowercase_spam in lowercase_text:
      return True
Exemplo n.º 18
0
def GetDestination(request, domain_name):
    """Based on the request, determines the map URL to redirect to."""
    # For backward compatibility, support the id= and crisis= parameters.
    label = request.get('id') or request.get('crisis')
    if not label:
        domain = domains.Domain.Get(domain_name
                                    or config.Get('primary_domain'))
        label = domain and domain.default_label or 'empty'
    if domain_name:
        url = request.root_path + '/' + domain_name + '/' + label
    else:
        url = request.root_path + '/' + label

    # Preserve all the query parameters except those that set the label.
    params = dict((key, value) for (key, value) in request.GET.items()
                  if key not in ['id', 'crisis'])
    return url + (params and '?' + urllib.urlencode(params) or '')
Exemplo n.º 19
0
  def _GetMap(self, label, domain):
    """Loads the model.Map instance being reviewed by label and domain.

    Args:
      label: A string, the published label for the map.
      domain: A string, the domain in which the map was created, eg gmail.com.

    Returns:
      The model.Map instance being reviewed

    Raises:
      base_handler.Error: If the map csnnot be found.
    """
    domain = domain or config.Get('primary_domain') or ''
    entry = model.CatalogEntry.Get(domain, label)
    if not entry:
      raise base_handler.Error(404, 'Map %r not found.' % label)
    map_object = model.Map.Get(entry.map_id)
    if not map_object:
      raise base_handler.Error(404, 'Map %r not found.' % label)
    return map_object
Exemplo n.º 20
0
def Keep():
    cfg = config.Get('mysql')
    conn = New(cfg['host'], cfg['port'], cfg['user'], cfg['passwd'],
               cfg['name'])
    return KeepThis('', conn)
Exemplo n.º 21
0
if __name__ == "__main__":
    save_filename = False
    email = False
    showalarms = False

    try:
        opts, args = getopt.getopt(sys.argv[1:], "", ["hours=", "config=", "file=", "email=", "alarms=",])
    except getopt.GetoptError:
        print ('dashboard.py --config <config yaml> --hours <hours> --email <email> --file <file> --alarms')
        sys.exit(2)
    for opt, arg in opts:
        if opt in ("-h", "--hours"):
            hours = int(arg)
        elif opt in ("-c", "--config"):
            config.Get(config=arg)
        elif opt in ("-f", "--file"):
            save_filename = arg
        elif opt in ("-e", "--email"):
            email = arg
        elif opt in ("-a", "--alarms"):
            showalarms = arg

    boto3.setup_default_session(
        aws_access_key_id=config.cfg['Credentials']['AWS_ID'],
        aws_secret_access_key=config.cfg['Credentials']['AWS_PASS'],
        region_name=config.cfg['Credentials']['region']
    )
    graphs = []

    for graphs_list in config.cfg["Graphs"]:
Exemplo n.º 22
0
def main(filename):
    doSideboard = config.Get('options', 'display_sideboard')

    #open user input decklist
    raw_decklist = open(str(filename), 'r')

    deck_list = decklist.parse_list(raw_decklist)

    raw_decklist.close()

    print(repr(deck_list))

    nstep = 1
    # create a header with the deck's name
    global fnt
    if deck_list.game == decklist.MTG:
        fnt = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts',
                         'belerensmallcaps-bold-webfont.ttf'), 14)
        fnt_title = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts',
                         'belerensmallcaps-bold-webfont.ttf'), 18)
        title = Image.new("RGB", (280, 34), "black")
        drawtitle = ImageDraw.Draw(title)
        drawtitle.text((10, 7),
                       os.path.basename(str(filename))[0:-4], (250, 250, 250),
                       font=fnt_title)
    elif deck_list.game == decklist.POKEMON:
        fnt = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts',
                         'ufonts.com_humanist521bt-ultrabold-opentype.otf'),
            10)
        fnt_title = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts',
                         'ufonts.com_humanist521bt-ultrabold-opentype.otf'),
            14)
        title = Image.new("RGB", (219, 35), "black")
        drawtitle = ImageDraw.Draw(title)
        drawtitle.text((10, 8),
                       os.path.basename(str(filename))[0:-4], (250, 250, 250),
                       font=fnt_title)
    elif deck_list.game == decklist.HEX:
        fnt = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts', 'Arial Bold.ttf'),
            16)
        fnt_title = ImageFont.truetype(
            os.path.join(globals.RESOURCES_PATH, 'fonts', 'Arial Bold.ttf'),
            18)
        title = Image.new("RGB", (320, 34), "black")
        nametitle = str(filename)[0:-4]
        nshard = 0
        for shard in [
                '[DIAMOND]', '[SAPPHIRE]', '[BLOOD]', '[RUBY]', '[WILD]'
        ]:
            #print nametitle,nshard
            if nametitle.find(shard) != -1:
                nametitle = nametitle.replace(shard, '')
                newshard = Image.open(
                    os.path.join(globals.RESOURCES_PATH, 'mana',
                                 shard + '.png')).resize((20, 20))
                title.paste(newshard, (10 + nshard * 20, 7))
                nshard = nshard + 1
        drawtitle = ImageDraw.Draw(title)
        drawtitle.text((15 + nshard * 20, 12),
                       os.path.basename(nametitle), (250, 250, 250),
                       font=fnt_title)

    ncountMB = len(deck_list.mainboard)
    ncountSB = len(deck_list.sideboard)
    ncount = ncountMB
    if ncountSB == 0:
        doSideboard = False
    if doSideboard:
        #create a Sideboard partition
        sideboard = Image.new("RGB", (280, 34), "black")
        drawtitle = ImageDraw.Draw(sideboard)
        sideboard_name = "Sideboard"
        if deck_list.game == decklist.HEX:
            sideboard_name = "Reserves"
        drawtitle.text((10, 7),
                       sideboard_name, (250, 250, 250),
                       font=fnt_title)
        ncount += ncountSB + 1

    #define the size of the canvas, incl. space for the title header
    if deck_list.game == decklist.MTG:
        deckwidth = 280
        deckheight = 34 * (ncount + 1)
        #for scrolling decklist
        deckwidth2 = 270 * (ncount + 1)
        deckheight2 = 34
    elif deck_list.game == decklist.POKEMON:
        deckwidth = 219
        deckheight = 35 * (ncount + 1)
    elif deck_list.game == decklist.HEX:
        deckwidth = 320
        deckheight = 35 * (ncount + 1)

    #reset the sideboard marker
    isSideboard = 0

    global deck
    deck = Image.new("RGB", (deckwidth, deckheight), "white")
    #for scrolling decklist
    global deck2
    deck2 = Image.new("RGB", (deckwidth2, deckheight2), "white")

    deck.paste(title, (0, 0))
    #for scrolling decklist
    title2 = title.crop((0, 0, 270, 34))
    deck2.paste(title2, (0, 0))

    #now read the decklist
    if deck_list.game == decklist.MTG:
        lands = []

        for card in deck_list.mainboard:
            #this step checks whether a specific art is requested by the user - provided via the set name

            if card.cost == "*":
                lands.append(card)
                continue
            draw_mtg_card(card, nstep)
            nstep = nstep + 1

        for card in lands:
            draw_mtg_card(card, nstep)
            nstep = nstep + 1

        if doSideboard:
            deck.paste(sideboard, (0, 34 * nstep))
            #for scrolling decklist
            sideboard2 = sideboard.crop((0, 0, 270, 34))
            deck2.paste(sideboard2, (270 * nstep, 0))
            nstep = nstep + 1
            for card in deck_list.sideboard:
                draw_mtg_card(card, nstep)
                nstep = nstep + 1

    elif deck_list.game == decklist.POKEMON:
        for card in deck_list.mainboard:
            quantity = card.quantity
            lookupScan, displayname = scraper.download_scanPKMN(
                card.name, card.set, card.collector_num)

            img = Image.open(lookupScan)

            #check if im has Alpha band...
            if img.mode != 'RGBA':
                img = img.convert('RGBA')

            #resize the gradient to the size of im...
            alpha = gradient.resize(img.size)

            #put alpha in the alpha band of im...
            img.putalpha(alpha)

            bkgd = Image.new("RGB", img.size, "black")
            bkgd.paste(img, (0, 0), mask=img)

            cut = bkgd.crop(
                (xtopPKMN, ytopPKMN + 90, xbotPKMN - 10, ybotPKMN + 100))
            cut = cut.resize((deckwidth, 34))

            draw = ImageDraw.Draw(cut)
            #create text outline
            draw.text((6, 11),
                      str(quantity) + '  ' + displayname, (0, 0, 0),
                      font=fnt)
            draw.text((8, 11),
                      str(quantity) + '  ' + displayname, (0, 0, 0),
                      font=fnt)
            draw.text((6, 13),
                      str(quantity) + '  ' + displayname, (0, 0, 0),
                      font=fnt)
            draw.text((8, 13),
                      str(quantity) + '  ' + displayname, (0, 0, 0),
                      font=fnt)
            #enter text
            draw.text((7, 12),
                      str(quantity) + '  ' + displayname, (250, 250, 250),
                      font=fnt)

            #place the cropped picture of the current card
            deck.paste(cut, (0, 35 * nstep))

            nstep = nstep + 1

    elif deck_list.game == decklist.HEX:
        banner = Image.new("RGB", (deckheight - 35, 50), "black")
        if len(deck_list.commander) > 0:
            cmdr = deck_list.commander[0]
            guid = cmdr.collector_num
            typeCM = cmdr.set

            drawbanner = ImageDraw.Draw(banner)
            drawbanner.text((15, 15),
                            str(cmdr.name), (250, 250, 250),
                            font=fnt_title)

            lookupScan = scraper.download_scanHexCM(cmdr.name, guid, typeCM)

            mainguyImg = Image.open(lookupScan)
            mainguycut = mainguyImg.crop((135, 55, 185, 275))

            banner = banner.rotate(90, expand=True)

            #check if im has Alpha band...
            if mainguycut.mode != 'RGBA':
                mainguycut = mainguycut.convert('RGBA')

            #resize the gradient to the size of im...
            alpha = Hexgradient.resize(mainguycut.size)

            #put alpha in the alpha band of im...
            mainguycut.putalpha(alpha)

            banner.paste(mainguycut, (0, 0), mask=mainguycut)

            deck.paste(banner, (0, 35))

        for card in deck_list.mainboard:
            draw_hex_card(card.name, card.collector_num, card.quantity, nstep)
            nstep = nstep + 1

        if doSideboard:
            deck.paste(sideboard, (50, 35 * nstep))
            nstep = nstep + 1
            for card in deck_list.sideboard:
                draw_hex_card(card.name, card.collector_num, card.quantity,
                              nstep)
                nstep = nstep + 1

    if deck_list.game == decklist.MTG:
        deck = deck.crop((0, 0, deckwidth - 10, deckheight))
        deck2 = deck2.crop((0, 0, deckwidth2, deckheight2 - 2))
    elif deck_list.game == decklist.POKEMON:
        deck = deck.crop((0, 0, deckwidth - 10, 35 * nstep))
    elif deck_list.game == decklist.HEX:
        deck = deck.crop((0, 0, deckwidth - 22, deckheight))

    output_path = str(filename)[0:-4] + ".png"
    deck.save(output_path)
    #for scrolling decklist
    output_path2 = str(filename)[0:-4] + "-scroll.png"
    deck2.save(output_path2)
    altpath = config.Get('options', 'output_path')
    if altpath is not None:
        deck.save(altpath)
    return output_path
Exemplo n.º 23
0
        "lastblock":
        "524e347f08e65c7d23bb7a24e6fae828f22db8a1d198bbe11aea655c18015a91"
    }
    return listsinceblock


class MainHandler(web.RequestHandler):
    async def get(self):
        self.write("JSONRPC server handles only POST requests")

    async def post(self):
        request = self.request.body.decode()
        if rpc_config.verbose > 1:
            print(request)
        response = await methods.dispatch(request)
        if not response.is_notification:

            self.write(response)


# see http://www.tornadoweb.org/en/stable/httpserver.html#http-server for ssl
# see http://www.tornadoweb.org/en/stable/web.html#tornado.web.Application.settings for logging and such
app = web.Application([(r"/", MainHandler)])

if __name__ == "__main__":
    rpc_config = config.Get()

    app.listen(rpc_config.rpcport)

    ioloop.IOLoop.current().start()
Exemplo n.º 24
0
def Action(actList, ruleId):
    log.debug("Action with: " + str(actList))
    action = actList[0].lower()
    if action == "Log".lower():
        log.debug("Rule says Log event for " + ' '.join(actList[1:]))
    elif action == "Play".lower():
        call(["omxplayer", "-o", actList[1], actList[2]])
    elif action == "Event".lower():
        if actList[1].lower() == "TimeOfDay".lower():
            events.IssueEvent(events.ids.TIMEOFDAY, actList[2])
        elif actList[1].lower() == "Alarm".lower():
            events.IssueEvent(events.ids.ALARM, actList[2])
        # Could have other events here...
    elif action == "synopsis":  # Was status
        emailAddress = config.Get("emailAddress")
        log.debug("About to send synopsis to " + emailAddress)
        if emailAddress != None:
            synopsis.BuildPage()  # Create synopsis page on demand
            with open("synopsis.txt", "r") as fh:  # Plain text of email
                emailText = fh.readlines()
            text = ''.join(emailText)
            with open("synopsis.html", "r") as fh:  # HTML of email
                emailHtml = fh.readlines()
            html = ''.join(emailHtml)
            sendmail.email("Vesta Status", text, html)  # See sendmail.py
        else:
            synopsis.problem(
                "NoEmail",
                "No emailAddress entry in config, needed to send synopsis")
    elif action == "email":  # All args are body of the text.  Fixed subject and email address
        emailAddress = config.Get("emailAddress")
        if emailAddress != None:
            emailBody = []
            for item in actList[1:]:
                emailBody.append(item)
            plainText = " ".join(emailBody)
            log.debug("Sending email with '" + plainText + "'")
            result = sendmail.email("Vesta Alert!", plainText, None)
            if result != 0:
                synopsis.problem(
                    "Email", "sendmail.email() failed with code " +
                    str(result) + " when trying to send:" + plainText)
        else:
            synopsis.problem("NoEmail", "No emailAddress entry in config")
    elif action == "override":  # Syntax is "Override <targetDevice> <targetDegC> <durationSecs>"
        devKey = devices.FindDev(actList[1])
        target = actList[2]
        timeSecs = actList[3]
        if devKey != None:
            schedule.Override(devKey, target, timeSecs)
    elif action == "set":  # Set a named variable to a value
        expression = "".join(
            actList[1:]
        )  # First recombine actList[1] onwards, with no spaces.  Now expression should be of the form "<var>=<val>"
        if "--" in expression:
            sep = expression.index("--")
            varName = expression[:sep]
            varVal = variables.Get(varName)
            if isNumber(varVal):
                newVal = str(eval(varVal + "-1"))
                variables.Set(varName, newVal)
                Run(
                    varName + "==" + newVal
                )  # Recurse! to see if any rules need running now that we've set a variable
            else:
                log.fault(varName + " not a number at " + expression)
        elif "++" in expression:
            sep = expression.index("++")
            varName = expression[:sep]
            varVal = variables.Get(varName)
            if isNumber(varVal):
                newVal = str(eval(varVal + "+1"))
                variables.Set(varName, newVal)
                Run(
                    varName + "==" + newVal
                )  # Recurse! to see if any rules need running now that we've set a variable
            else:
                log.fault(varName + " not a number at " + expression)
        elif "=" in expression:
            sep = expression.index("=")
            varName = expression[:sep]
            varVal = expression[sep + 1:]
            variables.Set(varName, varVal)
            Run(
                varName + "==" + varVal
            )  # Recurse! to see if any rules need running now that we've set a variable
        else:
            log.fault("Badly formatted rule at " + expression)
    elif action == "unset":  # Remove a named variable
        variables.Del(actList[1])
    else:  # Must be a command for a device, or group of devices
        if len(actList) >= 2:  # Check that we have a second arg...
            name = actList[1]  # Second arg is name
            if database.IsGroupName(name):  # Check if name is a groupName
                devKeyList = GetGroupDevs(name)
                for devKey in devKeyList:
                    CommandDev(action, devKey, actList,
                               ruleId)  # Command each device in list
            else:
                devKey = database.GetDevKey("userName", name)
                CommandDev(action, devKey, actList,
                           ruleId)  # Command one device
Exemplo n.º 25
0
def BuildPage():
    upTime = datetime.now() - iottime.appStartTime
    absUrl = config.Get("vestaURL", "")
    log.debug("Building status page")
    txt = open("synopsis.txt", "w")  # Create text file for txt
    html = open(
        "synopsis.html", "w"
    )  # Create local html file, so we can copy it for Apache to serve up, or mail directly
    html.write("\n<html><head>")  # Blank line at start
    html.write(
        "<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE, no-store, must-revalidate\">"
    )  # Try to force browser to discard any previous version of this page
    html.write("</head><body>")
    html.write("<center><h1>Vesta Status</h1>")
    txt.write("Vesta Status\n\n")
    writeLine(
        "At " + datetime.now().strftime("%H:%M") + " on " +
        datetime.now().strftime("%Y/%m/%d"), html, txt)
    writeLine("Uptime: %d days, %.2d:%.2d" %
              (upTime.days, upTime.seconds // 3600,
               (upTime.seconds // 60) % 60), html,
              txt)  # Cribbed from "uptime" command
    writeLine("", html, txt)  # Just newline
    keyList = database.GetAllDevKeys(
    )  # Get a list of all the device identifiers from the database
    noProblems = True
    restartCount = database.CountEvents(0, "App started",
                                        "date('now', '-1 days')")
    if restartCount > 0:
        noProblems = False
        writeLine(
            "App restarted " + str(restartCount) +
            " times in the last 24 hours", html, txt)
    else:  # Don't check availablilty of devices if app has restarted
        for devKey in keyList:  # Element 0 is hub, rest are devices
            if database.GetDeviceItem(devKey, "nwkId") != "0000":  # Ignore hub
                availability = presence.GetAvailability(devKey)
                if availability != "":  # If device missing even only occasionally, tell user (Empty string means "fine")
                    noProblems = False
                    writeLine(availability, html, txt)
    dbSize = database.GetFileSize()
    if (dbSize / len(keyList)) > (30 *
                                  1024):  # Arbitrary limit of 30K per device
        noProblems = False
        problem(
            "dbSize", "Database file size is " +
            "{0:.2f}".format(dbSize / (1024 * 1024)) + "MB which is " +
            "{0:.0f}".format((dbSize / len(keyList)) / 1024) + "KB per device")
    errList = glob.glob(
        "/home/pi/Vesta/*_err.log")  # Get list of all error logs
    numLogs = len(errList)
    if numLogs:
        noProblems = False
        if numLogs == 1:
            problem("error_logs", "1 error log")
        else:
            problem("error_logs", str(numLogs) + " error logs")
    if len(issues) > 0:
        noProblems = False
        for items in issues.values():
            writeLine(items, html, txt)
    if noProblems:
        writeLine("Everything OK!", html, txt)
    writeLine("", html, txt)  # Just newline
    writeLine("(Vesta v" + vesta.GetVersion() + ")", html, txt)
    html.write("<br><center><a href=\"" + absUrl +
               "/vesta/index.php\"><img src=\"" + absUrl +
               "/vesta/vestaLogo.png\" width=32 height=32 title=\"Home\"></a>")
    html.write("</body></html>")
    html.close()
    txt.close()
    os.system(
        "sudo cp synopsis.html /var/www/html/vesta"
    )  # So vesta.php can refer to it.  Will overrwrite any previous status
Exemplo n.º 26
0
def GetConfig(request, map_object=None, catalog_entry=None, xsrf_token=''):
  dev_mode = request.get('dev') and users.IsDeveloper()
  map_picker_items = GetMapPickerItems(
      catalog_entry and catalog_entry.domain or
      config.Get('primary_domain'), request.root_path)

  # Fill the cm_config dictionary.
  root = request.root_path
  xsrf_qs = '?xsrf_token=' + xsrf_token  # needed for all POST URLs
  result = {
      'dev_mode': dev_mode,
      'langs': base_handler.ALL_LANGUAGES,
      # Each endpoint that the JS client code uses gets an entry in config.
      'js_root': root + '/.js',
      'json_proxy_url': root + '/.jsonp',
      'kmlify_url': request.host_url + root + '/.kmlify',
      'login_url': users.GetLoginUrl(request.url),
      'logout_url': users.GetLogoutUrl(request.url),
      'map_picker_items': map_picker_items,
      'protect_url': root + '/.protect',
      'report_query_url': root + '/.api/reports',
      'report_post_url': root + '/.api/reports' + xsrf_qs,
      'vote_post_url': root + '/.api/votes' + xsrf_qs,
      'static_content_url': root + '/.static',
      'user_email': users.GetCurrent() and users.GetCurrent().email,
      'wms_configure_url': root + '/.wms/configure',
      'wms_tiles_url': root + '/.wms/tiles'
  }

  # Add settings from the selected client config, if any.
  result.update(GetClientConfig(request.get('client'),
                                request.headers.get('referer'), dev_mode))

  # Add the MapRoot data and other map-specific information.
  if catalog_entry:  # published map
    map_root = result['map_root'] = catalog_entry.map_root
    result['label'] = catalog_entry.label
    result['publisher_name'] = catalog_entry.publisher_name
    key = catalog_entry.map_version_key
  elif map_object:  # draft map
    map_root = result['map_root'] = map_object.map_root
    result['map_list_url'] = root + '/.maps'
    result['diff_url'] = root + '/.diff/' + map_object.id + xsrf_qs
    result['save_url'] = root + '/.api/maps/' + map_object.id + xsrf_qs
    result['share_url'] = root + '/.share/' + map_object.id + xsrf_qs
    result['api_maps_url'] = root + '/.api/maps'
    result['legend_url'] = root + '/.legend'
    result['wms_query_url'] = root + '/.wms/query'
    result['enable_editing'] = map_object.CheckAccess(perms.Role.MAP_EDITOR)
    result['draft_mode'] = True
    key = map_object.current_version_key

  # Parameters that depend on the MapRoot, for both published and draft maps.
  ui_region = request.get('gl')
  if map_object or catalog_entry:
    result['lang'] = base_handler.SelectLanguageForRequest(request, map_root)
    ui_region = map_root.get('region', ui_region)
    cache_key, sources = metadata.CacheSourceAddresses(key, result['map_root'])
    result['metadata'] = {s: METADATA_CACHE.Get(s) for s in sources}
    result['metadata_url'] = root + '/.metadata?ck=' + cache_key
    metadata.ActivateSources(sources)

  # Construct the URL for the Maps JavaScript API.
  api_url_params = {
      'sensor': 'false',
      'libraries': 'places,search,visualization,weather',
      'client': GetMapsApiClientId(request.host),
      'language': request.lang
  }
  if ui_region:
    api_url_params['region'] = ui_region
  result['maps_api_url'] = (MAPS_API_BASE_URL + '?' +
                            urllib.urlencode(api_url_params))

  maproot_url = request.get('maproot_url', '')
  if dev_mode or maproot_url.startswith(request.root_url + '/'):
    # It's always okay to fetch MapRoot JSON from a URL if it's from this app.
    # In developer mode only, allow MapRoot JSON from arbitrary URLs.
    result['maproot_url'] = maproot_url

  if dev_mode:
    # In developer mode only, allow query params to override the result.
    # Developers can also specify map_root directly as a query param.
    for name in (
        ClientConfig.properties().keys() + ['map_root', 'use_tab_panel']):
      value = request.get(name)
      if value:
        result[name] = json.loads(value)

  return result
Exemplo n.º 27
0
    def HandleRequest(self, **kwargs):
        """A wrapper around the Get or Post method defined in the handler class."""
        try:
            method = getattr(self, self.request.method.capitalize(), None)
            root_path = config.Get('root_path') or ''
            user = users.GetCurrent()

            if not method:
                raise Error(405,
                            '%s method not allowed.' % self.request.method)

            # Enforce login restrictions.
            self.CheckAccess()

            # Set self.auth according to the API key in the request, if specified.
            self.auth = GetAuthForRequest(self.request)

            # Require/allow domain name and user sign-in based on whether the method
            # takes arguments named 'domain' and 'user'.
            args, _, _, defaults = inspect.getargspec(method)
            required_args = args[:len(args) - len(defaults or [])]
            if 'domain' in kwargs and 'domain' not in args:
                raise Error(404, 'Not found.')
            if 'domain' in required_args and 'domain' not in kwargs:
                raise Error(400, 'Domain not specified.')
            if 'user' in args:
                kwargs['user'] = user
            if 'user' in required_args and not user:
                return self.redirect(users.GetLoginUrl(self.request.url))

            # Prepare an XSRF token if the user is signed in.
            if user:
                self.xsrf_token = GenerateXsrfToken(user.id)
                self.xsrf_tag = (
                    '<input type="hidden" name="xsrf_token" value="%s">' %
                    self.xsrf_token)

            # Require a valid XSRF token for all authenticated POST requests.
            if user and self.request.method == 'POST':
                xsrf_token = self.request.get('xsrf_token', '')
                if not ValidateXsrfToken(user.id, xsrf_token):
                    logging.warn('Bad xsrf_token %r for uid %r', xsrf_token,
                                 user.id)
                    # The window might have been idle for a day; go somewhere reasonable.
                    return self.redirect(root_path + '/.maps')

            # Fill in some useful request variables.
            self.request.lang = SelectLanguage(
                self.request.get('hl'),
                self.request.headers.get('accept-language'))
            self.request.root_path = root_path
            self.request.root_url = self.request.host_url + root_path

            # To prevent clickjacking attacks, disable framing by default.
            if not self.embeddable:
                self.response.headers['X-Frame-Options'] = 'DENY'

            # Call the handler, making nice pages for errors derived from Error.
            method(**kwargs)

        except RedirectToUrl as exception:
            return self.redirect(exception.url)
        except perms.AuthorizationError as exception:
            self.response.set_status(403, message=exception.message)
            self.response.out.write(
                self.RenderTemplate(
                    'unauthorized.html', {
                        'exception': exception,
                        'login_url': users.GetLoginUrl(self.request.url)
                    }))
        except perms.NotPublishableError as exception:
            self.response.set_status(403, message=exception.message)
            self.response.out.write(
                self.RenderTemplate(self.error_template,
                                    {'exception': exception}))
        except perms.NotCatalogEntryOwnerError as exception:
            # TODO(kpy): Either add a template for this type of error, or use an
            # error representation that can be handled by one common error template.
            self.response.set_status(403, message=exception.message)
            self.response.out.write(
                self.RenderTemplate(
                    self.error_template, {
                        'exception':
                        utils.Struct(
                            message='That publication label is owned '
                            'by someone else; you can\'t replace or delete it.'
                        )
                    }))
        except ApiError as exception:
            self.response.set_status(exception.status,
                                     message=exception.message)
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.out.write(exception.message + '\n')
        except Error as exception:
            self.response.set_status(exception.status,
                                     message=exception.message)
            self.response.out.write(
                self.RenderTemplate(self.error_template,
                                    {'exception': exception}))
Exemplo n.º 28
0
def EventHandler(eventId, eventArg):
    global ephemera, globalDevKey, pendingBinding, pendingBindingTimeoutS, pendingRptAttrId, msp_ota
    if eventId == events.ids.PREINIT:
        keyList = database.GetAllDevKeys(
        )  # Get a list of all the device identifiers from the database
        for i in range(
                100):  # Fudge to ensure we have enough pendingBinding entries
            pendingBinding.append(
                ""
            )  # Problem is that the devKey indices aren't consecutive (removed devices) and so
            pendingBindingTimeoutS.append(
                0
            )  # using the keyList isn't the same as for x in range(maxDevKey)
        for devKey in keyList:  # Hub and devices
            Init(devKey)  # Initialise dictionary and associated ephemera
            if database.GetDeviceItem(devKey, "nwkId") != "0000":  # Ignore hub
                SetTempVal(
                    devKey, "GetNextBatteryAfter",
                    datetime.now())  # Ask for battery shortly after startup
    if eventId == events.ids.INIT:
        msp_ota = config.Get("MSP_OTA")
    if eventId == events.ids.DEVICE_ANNOUNCE:
        if len(eventArg) >= 3:
            eui64 = eventArg[1]
            nwkId = eventArg[2]
            devKey = GetKey(nwkId)
            if devKey == None:  # Which will only be the case if we've not seen this short Id before
                devKey = database.GetDevKey("eui64", eui64)
                if devKey == None:  # Which will be the case if we've not seen the long Id either
                    devKey = Add(nwkId, eui64, eventArg[0])
                    log.debug("New key for new device is " + str(devKey))
                    if eventArg[0] == "SED":
                        SetTempVal(devKey, "PollingUntil",
                                   datetime.now() + timedelta(seconds=300))
                    events.Issue(
                        events.ids.NEWDEVICE, devKey
                    )  # Tell everyone that a new device has been seen, so it can be initialised
                else:  # Same long Id, but short Id needs updating after it has changed
                    database.SetDeviceItem(devKey, "nwkId", nwkId)
            else:
                NoteMsgDetails(devKey, eventArg)
            SetTempVal(
                devKey, "GetNextBatteryAfter", datetime.now()
            )  # Ask for battery shortly after Device Announce, either new or old one re-joining
    if eventId == events.ids.CHECKIN:  # See if we have anything to ask the device...
        if len(eventArg) >= 3:
            endPoint = eventArg[2]
            seq = "00"  # was seq = eventArg[3], but that's the RSSI
            devKey = GetKey(eventArg[1])
            if devKey != None:
                EnsureInBinding(
                    devKey, zcl.Cluster.PollCtrl
                )  # Assume CheckIn means PollCtrl must be in binding, so make sure this is up-to-date
                NoteMsgDetails(devKey, eventArg)
                if database.GetDeviceItem(devKey, "endPoints") == None:
                    database.SetDeviceItem(
                        devKey, "endPoints", endPoint
                    )  # Note endpoint that CheckIn came from, unless we already know this
                nwkId = database.GetDeviceItem(devKey, "nwkId")
                cmdRsp = Check(
                    devKey
                )  # Check to see if we want to know anything about the device
                if cmdRsp != None:
                    log.debug("Keep awake for 10 secs so we can send " +
                              cmdRsp[0])
                    queue.Jump(devKey, [
                        "AT+RAWZCL:" + nwkId + "," + endPoint + ",0020,11" +
                        seq + "00012800", "DFTREP"
                    ])  # Tell device to enter Fast Poll for 40qs (==10s)
                    SetTempVal(devKey, "PollingUntil",
                               datetime.now() + timedelta(seconds=10))
                    queue.EnqueueCmd(
                        devKey,
                        cmdRsp)  # This will go out after the Fast Poll Set
                else:
                    SetTempVal(
                        devKey, "PollingUntil",
                        datetime.now() + timedelta(seconds=2)
                    )  # Say that it's polling for a short while, so that we can tell it to stop(!)
                    queue.EnqueueCmd(devKey, [
                        "AT+RAWZCL:" + nwkId + "," + endPoint + ",0020,11" +
                        seq + "00000100", "DFTREP"
                    ])  # Tell device to stop Poll
            else:  # Unknown device, so assume it's been deleted from our database
                telegesis.Leave(
                    eventArg[1]
                )  # Tell device to leave the network, since we don't know anything about it
    if eventId == events.ids.TRIGGER or eventId == events.ids.BUTTON:
        if len(eventArg) >= 2:
            devKey = GetKey(
                eventArg[1]
            )  # Lookup device from network address in eventArg[1]
            if devKey != None:
                SetTempVal(
                    devKey, "PollingUntil",
                    datetime.now() + timedelta(seconds=1)
                )  # Say that it's polling for a very short while so that we can try to set up a PollCtrl cluster
    if eventId == events.ids.RXMSG:
        if eventArg[0] == "AddrResp" and eventArg[1] == "00" and len(
                eventArg) >= 3:
            devKey = GetKey(eventArg[2])
            if devKey != None:
                database.SetDeviceItem(devKey, "eui64", eventArg[1])
        elif eventArg[0] == "ActEpDesc" and len(eventArg) >= 3:
            if "00" == eventArg[2]:
                devKey = GetKey(eventArg[1])
                if devKey != None:
                    database.SetDeviceItem(devKey, "endPoints",
                                           eventArg[3])  # Note first endpoint
        elif eventArg[0] == "SimpleDesc" and len(eventArg) >= 3:
            if "00" == eventArg[2]:
                globalDevKey = GetKey(
                    eventArg[1]
                )  # Is multi-line response, so expect rest of response and use this global index until it's all finished
            elif "82" == eventArg[2]:  # 82 == Invalid endpoint
                devKey = GetKey(eventArg[1])
                events.Issue(events.ids.RXERROR, int(
                    eventArg[2],
                    16))  # Tell system that we're aborting this command
        elif eventArg[0] == "InCluster" and len(eventArg) >= 2:
            if globalDevKey != None:
                database.SetDeviceItem(
                    globalDevKey, "inClusters", str(eventArg[1:])
                )  # Store whole list from arg[1] to arg[n]
        elif eventArg[0] == "OutCluster" and len(eventArg) >= 2:
            if globalDevKey != None:
                NoteMsgDetails(
                    globalDevKey, eventArg
                )  # Must do this so that we can remove RSSI and LQI if they're there, to avoid these values being interpreted as clusters
                database.SetDeviceItem(
                    globalDevKey, "outClusters", str(eventArg[1:])
                )  # Store whole list from arg[1] to arg[n]
            globalDevKey = None  # We've finished with this global for now
        elif eventArg[0] == "RESPATTR" and len(eventArg) >= 7:
            devKey = GetKey(eventArg[1])
            if devKey != None:
                NoteMsgDetails(devKey, eventArg)
                if len(
                        eventArg
                ) >= 7:  # Check for number of args after possibly removing RSSI and LQI
                    ep = eventArg[2]
                    clusterId = eventArg[3]
                    attrId = eventArg[4]
                    if "00" == eventArg[5]:
                        attrVal = eventArg[6]
                        SetAttrVal(devKey, clusterId, attrId, attrVal)
                    else:
                        SetAttrVal(devKey, clusterId, attrId,
                                   "Failed (error " + eventArg[5] +
                                   ")")  # So that we don't keep asking
        elif eventArg[0] == "RESPMATTR" and len(eventArg) >= 8:
            devKey = GetKey(eventArg[1])
            if devKey != None:
                NoteMsgDetails(devKey, eventArg)
                if len(
                        eventArg
                ) >= 8:  # Check for number of args after possibly removing RSSI and LQI
                    ep = eventArg[2]
                    mfgId = eventArg[3]
                    clusterId = eventArg[4]
                    attrId = eventArg[5]
                    if "00" == eventArg[6]:
                        attrVal = eventArg[7]
                        SetAttrVal(devKey, clusterId, attrId, attrVal)
        elif eventArg[0] == "REPORTATTR" and len(eventArg) >= 7:
            devKey = GetKey(eventArg[1])
            if devKey != None:
                ep = eventArg[2]
                clusterId = eventArg[3]
                attrId = eventArg[4]
                attrType = eventArg[5]
                attrVal = eventArg[6]
                if clusterId == zcl.Cluster.MultistateInput and attrId == zcl.Attribute.PresentValue:
                    args = [attrVal, eventArg[1]]
                    events.Issue(events.ids.MULTISTATE, args)
                    return  # Ignore reports on Basic cluster (eg lumi.sensor_cube when it joins will send this)
                #if clusterId == zcl.Cluster.Basic:
                #    return # Ignore reports on Basic cluster (eg lumi.sensor_cube when it joins will send this)
                NoteMsgDetails(devKey, eventArg)
                EnsureReporting(
                    devKey, clusterId, attrId, attrVal
                )  # Make sure reports are happening at the correct frequency and update device if not
                SetAttrVal(devKey, clusterId, attrId, attrVal)
                NoteReporting(devKey, clusterId, attrId)
            else:  # Unknown device, so assume it's been deleted from our database
                telegesis.Leave(
                    eventArg[1]
                )  # Tell device to leave the network, since we don't know anything about it
        elif eventArg[0] == "Bind" and len(
                eventArg) >= 2:  # Binding Response from device
            devKey = GetKey(eventArg[1])
            if devKey != None:
                if pendingBinding[devKey]:
                    binding = eval(
                        database.GetDeviceItem(devKey, "binding", "[]"))
                    if pendingBinding[
                            devKey] not in binding:  # Only put it in once, even if we get multiple responses
                        binding.append(pendingBinding[devKey])
                        database.SetDeviceItem(devKey, "binding", str(binding))
                    pendingBinding[devKey] = None
        elif eventArg[0] == "CFGRPTRSP" and len(
                eventArg) >= 5:  # Configure Report Response from device
            devKey = GetKey(eventArg[1])
            status = eventArg[4]
            if devKey != None and status == "00":
                clusterId = eventArg[3]
                attrId = pendingRptAttrId  # Need to remember this, since it doesn't appear in CFGRPTRSP
                NoteReporting(devKey, clusterId, attrId)
                pendingRptAttrId = None  # Ready for the next report
        elif eventArg[0] == "CWSCHEDULE":
            heating.ParseCWShedule(eventArg)
        elif eventArg[0] == "DFTREP":
            devKey = GetKey(eventArg[1])
            NoteMsgDetails(devKey, eventArg)
        #else:   # Unrecognised message, but we still want to extract OOB info
        #    if len(eventArg) >= 2:
        #        devKey = GetKey(eventArg[1])    # Assume this is sensible
        #        if devKey != None:
        #            NoteMsgDetails(devKey, eventArg)
    #if eventId == events.ids.BUTTON:
    #    devKey = GetKey(eventArg[1]) # Lookup device from network address in eventArg[1]
    #    NoteMsgDetails(devKey, eventArg)
    if eventId == events.ids.RXERROR:
        globalDevKey = None  # We've finished with this global if we get an error
    if eventId == events.ids.SECONDS:
        for devKey in devDict:  # Go through devDict, pulling out each entry
            if devDict[devKey] >= 0:  # Make sure device hasn't been deleted
                if IsListening(devKey):  # True if FFD, ZED or Polling
                    devIndex = GetIndexFromKey(devKey)
                    if expRsp[
                            devIndex] == None:  # We don't have a message in flight
                        if queue.IsEmpty(devKey):
                            cmdRsp = Check(devKey)
                            if cmdRsp:
                                queue.EnqueueCmd(
                                    devKey, cmdRsp
                                )  # Queue up anything we ought to know
                        cmdRsp = queue.DequeueCmd(
                            devKey)  # Pull first item from queue
                        if cmdRsp != None:
                            log.debug("Sending " + str(cmdRsp))
                            expRsp[devIndex] = cmdRsp[1]  # Note response
                            expRspTimeoutS[
                                devIndex] = 2  # If we've not heard back after 2 seconds, it's probably got lost, so try again
                            telegesis.TxCmd(cmdRsp[0])  # Send command directly
                    else:  # We're expecting a response, so time it out
                        expRspTimeoutS[
                            devIndex] = expRspTimeoutS[devIndex] - eventArg
                        if expRspTimeoutS[devIndex] <= 0:
                            expRsp[devIndex] = None
                    if pendingBinding[
                            devKey]:  # Make sure we timeout pendingBinding
                        pendingBindingTimeoutS[
                            devKey] = pendingBindingTimeoutS[devKey] - eventArg
                        if pendingBindingTimeoutS[devKey] <= 0:
                            pendingBinding[devKey] = None
            offAt = GetTempVal(devKey, "SwitchOff@")
            if offAt:
                if datetime.now() >= offAt:
                    DelTempVal(devKey, "SwitchOff@")
                    devcmds.SwitchOff(devKey)
            fadeDownAt = GetTempVal(devKey, "FadeDown@")
            if fadeDownAt:
                if datetime.now() >= fadeDownAt:
                    DelTempVal(devKey, "FadeDown@")
                    devcmds.Dim(devKey, 0)
                    devcmds.SwitchOff(devKey)  # Switch off after dim command
            pirOffAt = GetTempVal(devKey, "PirInactive@")
            if pirOffAt:
                if datetime.now() >= pirOffAt:
                    DelTempVal(devKey, "PirInactive@")
                    newState = "inactive"
                    database.NewEvent(devKey, newState)
                    Rule(devKey, newState)
Exemplo n.º 29
0
def SetAttrVal(devKey, clstrId, attrId, value):
    global msp_ota
    if clstrId == zcl.Cluster.PowerConfig and attrId == zcl.Attribute.Batt_Percentage:
        SetTempVal(devKey, "GetNextBatteryAfter",
                   datetime.now() +
                   timedelta(seconds=86400))  # Ask for battery every day
        if value != "FF":
            try:
                varVal = int(
                    int(value, 16) / 2
                )  # Arrives in 0.5% increments, but drop fractional component
            except ValueError:
                varVal = None
            if varVal != None:
                log.debug("Battery is " + str(varVal) +
                          "%.  Get next reading at " +
                          str(GetTempVal(devKey, "GetNextBatteryAfter")))
                database.LogItem(devKey, "BatteryPercentage",
                                 varVal)  # For web page
                lowBatt = int(config.Get("lowBattery", "5"))
                if varVal < lowBatt:
                    devName = database.GetDeviceItem(devKey, "userName")
                    synopsis.problem(
                        devName + "_batt",
                        devName + " low battery (" + str(varVal) + "%)")
    if clstrId == zcl.Cluster.Temperature and attrId == zcl.Attribute.Celsius:
        if value != "FF9C" and value != "8000":  # Don't know where this value (of -100) comes from, but seems to mean "Illegal temp", although it should be -1'C
            try:
                varVal = int(value, 16) / 100  # Arrives in 0.01'C increments
                database.LogItem(devKey, "TemperatureCelsius",
                                 varVal)  # For web page
            except ValueError:
                log.debug("Bad temperature of " + value)
    if clstrId == zcl.Cluster.OnOff and attrId == zcl.Attribute.OnOffState:
        if isnumeric(value, 16):
            oldState = database.GetLatestLoggedValue(devKey, "State")
            if int(value, 16) == 0:
                newState = "SwitchOff"
            else:
                newState = "SwitchOn"
            if oldState != newState:
                database.UpdateLoggedItem(
                    devKey, "State",
                    newState)  # So that we can access it from the rules later
                database.NewEvent(devKey, newState)
                Rule(devKey, newState)
            expectedState = GetTempVal(devKey, "ExpectOnOff")
            if expectedState != None:
                if newState != expectedState:
                    if expectedState == "SwitchOn":
                        devcmds.SwitchOn(devKey)  # Re-issue command
                    else:  # Assume SwitchOff
                        devcmds.SwitchOff(devKey)  # Re-issue command
                else:  # We got the expected result
                    DelTempVal(devKey, "ExpectOnOff")
    if clstrId == zcl.Cluster.Time and attrId == zcl.Attribute.LocalTime:
        if isnumeric(value, 16):
            varVal = int(value,
                         16)  # Arrives in Watts, so store it in the same way
            log.debug("Raw time:" + str(varVal))
            timeStr = iottime.FromZigbee(varVal)
            log.debug("Human time:" + timeStr)
            database.UpdateLoggedItem(devKey, "Time",
                                      timeStr)  # Just store latest time string
    if clstrId == zcl.Cluster.SimpleMetering and attrId == zcl.Attribute.InstantaneousDemand:
        if isnumeric(value, 16):
            varVal = int(value,
                         16)  # Arrives in Watts, so store it in the same way
            inClstr = database.GetDeviceItem(
                devKey, "inClusters"
            )  # Assume we have a list of clusters if we get this far
            if zcl.Cluster.OnOff not in inClstr:  # Thus device is powerclamp (has simplemetering but no OnOff)
                database.UpdateLoggedItem(
                    devKey, "State",
                    str(varVal) + "W"
                )  # So that we can access it from the rules later, or show it on the web
            database.UpdateLoggedItem(devKey, "PowerReadingW",
                                      varVal)  # Just store latest reading
    if clstrId == zcl.Cluster.SimpleMetering and attrId == zcl.Attribute.CurrentSummationDelivered:
        if isnumeric(value, 16):
            varVal = int(
                value, 16
            )  # Arrives in accumulated WattHours, so store it in the same way
            database.LogItem(devKey, "EnergyConsumedWh", varVal)
    if clstrId == zcl.Cluster.IAS_Zone and attrId == zcl.Attribute.Zone_Type:
        database.SetDeviceItem(devKey, "iasZoneType", value)
    if clstrId == zcl.Cluster.Basic:
        if attrId == zcl.Attribute.Model_Name:
            database.SetDeviceItem(devKey, "modelName", value)
        if attrId == zcl.Attribute.Manuf_Name:
            database.SetDeviceItem(devKey, "manufName", value)
    if clstrId == zcl.Cluster.OTA or clstrId == msp_ota:
        if attrId == zcl.Attribute.firmwareVersion:
            database.SetDeviceItem(devKey, "firmwareVersion", value)
    if clstrId == zcl.Cluster.PollCtrl:
        if attrId == zcl.Attribute.LongPollIntervalQs:
            varVal = str(float(int(value, 16) /
                               4))  # Value arrives in units of quarter seconds
            database.SetDeviceItem(
                devKey, "longPollInterval", varVal
            )  # For web page and also to see whether to wait for CheckIn or just send messages (if <6 secs)
    if clstrId == zcl.Cluster.Thermostat:
        if attrId == zcl.Attribute.LocalTemp:
            if isnumeric(value, 16):
                varVal = int(value, 16) / 100  # Arrives in 0.01'C increments
                database.LogItem(devKey, "SourceCelsius",
                                 varVal)  # For web page
                src = varVal
                tgt = database.GetLatestLoggedValue(devKey, "TargetCelsius")
                database.UpdateLoggedItem(
                    devKey, "State", "source " + str(src) + "'C/target " +
                    str(tgt) + "'C")  # So that we can show it on the web
        if attrId == zcl.Attribute.OccupiedHeatingSetPoint:
            if isnumeric(value, 16):
                varVal = int(value, 16) / 100  # Arrives in 0.01'C increments
                database.LogItem(devKey, "TargetCelsius",
                                 varVal)  # For web page
                tgt = varVal
                src = database.GetLatestLoggedValue(devKey, "SourceCelsius")
                database.UpdateLoggedItem(
                    devKey, "State", "source " + str(src) + "'C/target " +
                    str(tgt) + "'C")  # So that we can show it on the web
    if clstrId == zcl.Cluster.Time:
        if attrId == zcl.Attribute.Time:
            if isnumeric(value, 16):
                varVal = int(value,
                             16)  # Arrives in seconds since 1st Jan 2000
                timeStamp = iottime.FromZigbee(varVal)
                database.LogItem(devKey, "time",
                                 str(timeStamp))  # For web page
Exemplo n.º 30
0
def Check(devKey):
    global pendingBinding, msp_ota
    if devKey == 0: return  # We don't need anything from the hub
    nwkId = database.GetDeviceItem(devKey, "nwkId")
    if None == nwkId:
        return  # Make sure it's a real device before continuing (it may have just been deleted)
    ep = database.GetDeviceItem(devKey, "endPoints")
    if None == ep:
        return (["AT+ACTEPDESC:" + nwkId + "," + nwkId, "ActEpDesc"])
    eui = database.GetDeviceItem(devKey, "eui64")
    if None == eui: return (["AT+EUIREQ:" + nwkId + "," + nwkId, "AddrResp"])
    inClstr = database.GetDeviceItem(
        devKey, "inClusters",
        "[]")  # Assume we have a list of clusters if we get this far
    if "[]" == inClstr:
        return ([
            "AT+SIMPLEDESC:" + nwkId + "," + nwkId + "," + ep, "OutCluster"
        ])
    outClstr = database.GetDeviceItem(devKey, "outClusters", "[]")
    binding = database.GetDeviceItem(devKey, "binding" "[]")
    if str(pendingBinding[devKey]
           ) == "":  # Only try to add one binding per device at once
        if zcl.Cluster.PollCtrl in inClstr and zcl.Cluster.PollCtrl not in binding:
            return SetBinding(
                devKey, zcl.Cluster.PollCtrl,
                "01")  # 01 is our endpoint we want CHECKIN messages to come to
        if zcl.Cluster.OnOff in outClstr and zcl.Cluster.OnOff not in binding:  # If device sends OnOff commands (eg a Button)
            return SetBinding(
                devKey, zcl.Cluster.OnOff, "0A"
            )  # 0A is our endpoint we want messages to come to (so that we get TOGGLE, ON and OFF commands)
        if zcl.Cluster.Temperature in inClstr and zcl.Cluster.Temperature not in binding:
            return SetBinding(
                devKey, zcl.Cluster.Temperature, "01"
            )  # 01 is our endpoint we want Temperature reports to come to
        if zcl.Cluster.SimpleMetering in inClstr and zcl.Cluster.SimpleMetering not in binding:
            return SetBinding(
                devKey, zcl.Cluster.SimpleMetering, "01"
            )  # 01 is our endpoint we want SimpleMetering messages to come to
        if zcl.Cluster.Thermostat in inClstr and zcl.Cluster.Thermostat not in binding:
            return SetBinding(
                devKey, zcl.Cluster.Thermostat, "01"
            )  # 01 is our endpoint we want Thermostat messages to come to
    if zcl.Cluster.IAS_Zone in inClstr:
        if None == database.GetDeviceItem(devKey, "iasZoneType"):
            return telegesis.ReadAttr(
                nwkId, ep, zcl.Cluster.IAS_Zone, zcl.Attribute.Zone_Type
            )  # Get IAS device type (PIR or contact, etc.)
    if zcl.Cluster.Basic in inClstr:
        if None == database.GetDeviceItem(devKey, "modelName"):
            return telegesis.ReadAttr(
                nwkId, ep, zcl.Cluster.Basic,
                zcl.Attribute.Model_Name)  # Get Basic's Device Name
        if None == database.GetDeviceItem(devKey, "manufName"):
            return telegesis.ReadAttr(
                nwkId, ep, zcl.Cluster.Basic,
                zcl.Attribute.Manuf_Name)  # Get Basic's Manufacturer Name
    if zcl.Cluster.PowerConfig in inClstr and "SED" == database.GetDeviceItem(
            devKey, "devType"):
        checkBatt = GetTempVal(devKey, "GetNextBatteryAfter")
        if checkBatt != None:
            if datetime.now() > checkBatt:
                log.debug("Now = " + str(datetime.now()) +
                          " and checkBatt = " + str(checkBatt))
                return telegesis.ReadAttr(
                    nwkId, ep, zcl.Cluster.PowerConfig,
                    zcl.Attribute.Batt_Percentage)  # Get Battery percentage
    if zcl.Cluster.PollCtrl in inClstr:
        if None == database.GetDeviceItem(devKey, "longPollInterval"):
            return telegesis.ReadAttr(
                nwkId, ep, zcl.Cluster.PollCtrl, zcl.Attribute.
                LongPollIntervalQs)  # Get Poll Control's Long poll interval
    if zcl.Cluster.OTA in outClstr:
        if None == database.GetDeviceItem(devKey, "firmwareVersion"):
            return ("AT+READCATR:" + nwkId + "," + ep + ",0," +
                    zcl.Cluster.OTA + "," + zcl.Attribute.firmwareVersion,
                    "RESPATTR"
                    )  # Get OTA's Version number as a string of hex digits
    if msp_ota != None and msp_ota in outClstr:
        if None == database.GetDeviceItem(devKey, "firmwareVersion"):
            return ("AT+READMCATR:" + nwkId + "," + ep + ",0," +
                    config.Get(mfgId) + "," + msp_ota + "," +
                    zcl.Attribute.firmwareVersion, "RESPMATTR"
                    )  # Get OTA's Version number as a string of hex digits
    reporting = database.GetDeviceItem(devKey, "reporting", "[]")
    if zcl.Cluster.PowerConfig in binding and "SED" == database.GetDeviceItem(
            devKey, "devType"):
        atCmd = CheckReporting(
            devKey, reporting, "batteryReporting", zcl.Cluster.PowerConfig,
            zcl.Attribute.Batt_Percentage, zcl.AttributeTypes.Uint8,
            "43200,43200,2"
        )  # Default temperature reporting is "Every 12 hours"
        if atCmd != None: return atCmd
    if zcl.Cluster.Temperature in binding:
        atCmd = CheckReporting(
            devKey, reporting, "temperatureReporting", zcl.Cluster.Temperature,
            zcl.Attribute.Celsius, zcl.AttributeTypes.Uint16, "300,3600,100"
        )  # Default temperature reporting is "between 5 mins and 1 hr, or +/- 1.00'C"
        if atCmd != None: return atCmd
    if zcl.Cluster.SimpleMetering in binding:
        atCmd = CheckReporting(
            devKey, reporting, "powerReporting", zcl.Cluster.SimpleMetering,
            zcl.Attribute.InstantaneousDemand, zcl.AttributeTypes.Sint24,
            "-1,-1,10"
        )  # Default power reporting is "between 5 seconds and 15 minutes, or +/- 10W"
        if atCmd != None: return atCmd
        atCmd = CheckReporting(
            devKey, reporting, "energyConsumedReporting",
            zcl.Cluster.SimpleMetering,
            zcl.Attribute.CurrentSummationDelivered, zcl.AttributeTypes.Uint48,
            "-1,-1,100"
        )  # Default energy consumed reporting is "between 1 minute and 15 minutes, or +100Wh"
        if atCmd != None: return atCmd
        atCmd = CheckReporting(
            devKey, reporting, "energyGeneratedReporting",
            zcl.Cluster.SimpleMetering, zcl.Attribute.CurrentSummationReceived,
            zcl.AttributeTypes.Uint48, "-1,-1,0"
        )  # Default energy generated reporting is "never" (-1 as max)
        if atCmd != None: return atCmd
    if zcl.Cluster.Thermostat in binding:
        atCmd = CheckReporting(
            devKey, reporting, "targetTempReporting", zcl.Cluster.Thermostat,
            zcl.Attribute.OccupiedHeatingSetPoint, zcl.AttributeTypes.Sint16,
            "60,900,100"
        )  # Default target temperature reporting is "between 1 minute and 15 minutes, or +/-1.00'C"
        if atCmd != None: return atCmd
    if GetTempVal(devKey, "JustSentOnOff"):
        DelTempVal(devKey, "JustSentOnOff")
        return telegesis.ReadAttr(
            nwkId, ep, zcl.Cluster.OnOff,
            zcl.Attribute.OnOffState)  # Get OnOff state after sending toggle
    return None